@clinebot/llms 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/README.md +198 -0
  2. package/dist/config-browser.d.ts +3 -0
  3. package/dist/config.d.ts +3 -0
  4. package/dist/index.browser.d.ts +4 -0
  5. package/dist/index.browser.js +1 -0
  6. package/dist/index.d.ts +5 -0
  7. package/dist/index.js +7 -0
  8. package/dist/models/generated-access.d.ts +4 -0
  9. package/dist/models/generated-provider-loaders.d.ts +13 -0
  10. package/dist/models/generated.d.ts +14 -0
  11. package/dist/models/index.d.ts +43 -0
  12. package/dist/models/models-dev-catalog.d.ts +32 -0
  13. package/dist/models/providers/aihubmix.d.ts +5 -0
  14. package/dist/models/providers/anthropic.d.ts +53 -0
  15. package/dist/models/providers/asksage.d.ts +5 -0
  16. package/dist/models/providers/baseten.d.ts +5 -0
  17. package/dist/models/providers/bedrock.d.ts +7 -0
  18. package/dist/models/providers/cerebras.d.ts +7 -0
  19. package/dist/models/providers/claude-code.d.ts +4 -0
  20. package/dist/models/providers/cline.d.ts +34 -0
  21. package/dist/models/providers/deepseek.d.ts +8 -0
  22. package/dist/models/providers/dify.d.ts +5 -0
  23. package/dist/models/providers/doubao.d.ts +7 -0
  24. package/dist/models/providers/fireworks.d.ts +8 -0
  25. package/dist/models/providers/gemini.d.ts +9 -0
  26. package/dist/models/providers/groq.d.ts +8 -0
  27. package/dist/models/providers/hicap.d.ts +5 -0
  28. package/dist/models/providers/huawei-cloud-maas.d.ts +5 -0
  29. package/dist/models/providers/huggingface.d.ts +6 -0
  30. package/dist/models/providers/index.d.ts +45 -0
  31. package/dist/models/providers/litellm.d.ts +5 -0
  32. package/dist/models/providers/lmstudio.d.ts +5 -0
  33. package/dist/models/providers/minimax.d.ts +7 -0
  34. package/dist/models/providers/mistral.d.ts +5 -0
  35. package/dist/models/providers/moonshot.d.ts +7 -0
  36. package/dist/models/providers/nebius.d.ts +7 -0
  37. package/dist/models/providers/nous-research.d.ts +7 -0
  38. package/dist/models/providers/oca.d.ts +9 -0
  39. package/dist/models/providers/ollama.d.ts +5 -0
  40. package/dist/models/providers/openai-codex.d.ts +10 -0
  41. package/dist/models/providers/openai.d.ts +9 -0
  42. package/dist/models/providers/opencode.d.ts +10 -0
  43. package/dist/models/providers/openrouter.d.ts +7 -0
  44. package/dist/models/providers/qwen-code.d.ts +7 -0
  45. package/dist/models/providers/qwen.d.ts +7 -0
  46. package/dist/models/providers/requesty.d.ts +6 -0
  47. package/dist/models/providers/sambanova.d.ts +7 -0
  48. package/dist/models/providers/sapaicore.d.ts +7 -0
  49. package/dist/models/providers/together.d.ts +8 -0
  50. package/dist/models/providers/vercel-ai-gateway.d.ts +5 -0
  51. package/dist/models/providers/vertex.d.ts +7 -0
  52. package/dist/models/providers/xai.d.ts +8 -0
  53. package/dist/models/providers/zai.d.ts +7 -0
  54. package/dist/models/query.d.ts +181 -0
  55. package/dist/models/registry.d.ts +123 -0
  56. package/dist/models/schemas/index.d.ts +7 -0
  57. package/dist/models/schemas/model.d.ts +340 -0
  58. package/dist/models/schemas/query.d.ts +191 -0
  59. package/dist/providers/handlers/ai-sdk-community.d.ts +46 -0
  60. package/dist/providers/handlers/ai-sdk-provider-base.d.ts +32 -0
  61. package/dist/providers/handlers/anthropic-base.d.ts +26 -0
  62. package/dist/providers/handlers/asksage.d.ts +12 -0
  63. package/dist/providers/handlers/auth.d.ts +5 -0
  64. package/dist/providers/handlers/base.d.ts +55 -0
  65. package/dist/providers/handlers/bedrock-base.d.ts +23 -0
  66. package/dist/providers/handlers/bedrock-client.d.ts +4 -0
  67. package/dist/providers/handlers/community-sdk.d.ts +97 -0
  68. package/dist/providers/handlers/fetch-base.d.ts +18 -0
  69. package/dist/providers/handlers/gemini-base.d.ts +25 -0
  70. package/dist/providers/handlers/index.d.ts +19 -0
  71. package/dist/providers/handlers/openai-base.d.ts +54 -0
  72. package/dist/providers/handlers/openai-responses.d.ts +64 -0
  73. package/dist/providers/handlers/providers.d.ts +43 -0
  74. package/dist/providers/handlers/r1-base.d.ts +62 -0
  75. package/dist/providers/handlers/registry.d.ts +106 -0
  76. package/dist/providers/handlers/vertex.d.ts +32 -0
  77. package/dist/providers/index.d.ts +100 -0
  78. package/dist/providers/public.browser.d.ts +2 -0
  79. package/dist/providers/public.d.ts +3 -0
  80. package/dist/providers/shared/openai-compatible.d.ts +10 -0
  81. package/dist/providers/transform/ai-sdk-community-format.d.ts +9 -0
  82. package/dist/providers/transform/anthropic-format.d.ts +24 -0
  83. package/dist/providers/transform/content-format.d.ts +3 -0
  84. package/dist/providers/transform/gemini-format.d.ts +19 -0
  85. package/dist/providers/transform/index.d.ts +10 -0
  86. package/dist/providers/transform/openai-format.d.ts +36 -0
  87. package/dist/providers/transform/r1-format.d.ts +26 -0
  88. package/dist/providers/types/config.d.ts +261 -0
  89. package/dist/providers/types/handler.d.ts +71 -0
  90. package/dist/providers/types/index.d.ts +11 -0
  91. package/dist/providers/types/messages.d.ts +139 -0
  92. package/dist/providers/types/model-info.d.ts +32 -0
  93. package/dist/providers/types/provider-ids.d.ts +63 -0
  94. package/dist/providers/types/settings.d.ts +308 -0
  95. package/dist/providers/types/stream.d.ts +106 -0
  96. package/dist/providers/utils/index.d.ts +7 -0
  97. package/dist/providers/utils/retry.d.ts +38 -0
  98. package/dist/providers/utils/stream-processor.d.ts +110 -0
  99. package/dist/providers/utils/tool-processor.d.ts +34 -0
  100. package/dist/sdk.d.ts +18 -0
  101. package/dist/types.d.ts +60 -0
  102. package/package.json +66 -0
  103. package/src/catalog.ts +20 -0
  104. package/src/config-browser.ts +11 -0
  105. package/src/config.ts +49 -0
  106. package/src/index.browser.ts +9 -0
  107. package/src/index.ts +10 -0
  108. package/src/live-providers.test.ts +137 -0
  109. package/src/models/generated-access.ts +41 -0
  110. package/src/models/generated-provider-loaders.ts +166 -0
  111. package/src/models/generated.ts +11997 -0
  112. package/src/models/index.ts +271 -0
  113. package/src/models/models-dev-catalog.test.ts +161 -0
  114. package/src/models/models-dev-catalog.ts +161 -0
  115. package/src/models/providers/aihubmix.ts +19 -0
  116. package/src/models/providers/anthropic.ts +60 -0
  117. package/src/models/providers/asksage.ts +19 -0
  118. package/src/models/providers/baseten.ts +21 -0
  119. package/src/models/providers/bedrock.ts +30 -0
  120. package/src/models/providers/cerebras.ts +24 -0
  121. package/src/models/providers/claude-code.ts +51 -0
  122. package/src/models/providers/cline.ts +25 -0
  123. package/src/models/providers/deepseek.ts +33 -0
  124. package/src/models/providers/dify.ts +17 -0
  125. package/src/models/providers/doubao.ts +33 -0
  126. package/src/models/providers/fireworks.ts +34 -0
  127. package/src/models/providers/gemini.ts +43 -0
  128. package/src/models/providers/groq.ts +33 -0
  129. package/src/models/providers/hicap.ts +18 -0
  130. package/src/models/providers/huawei-cloud-maas.ts +18 -0
  131. package/src/models/providers/huggingface.ts +22 -0
  132. package/src/models/providers/index.ts +162 -0
  133. package/src/models/providers/litellm.ts +19 -0
  134. package/src/models/providers/lmstudio.ts +22 -0
  135. package/src/models/providers/minimax.ts +34 -0
  136. package/src/models/providers/mistral.ts +19 -0
  137. package/src/models/providers/moonshot.ts +34 -0
  138. package/src/models/providers/nebius.ts +24 -0
  139. package/src/models/providers/nous-research.ts +21 -0
  140. package/src/models/providers/oca.ts +30 -0
  141. package/src/models/providers/ollama.ts +18 -0
  142. package/src/models/providers/openai-codex.ts +30 -0
  143. package/src/models/providers/openai.ts +43 -0
  144. package/src/models/providers/opencode.ts +28 -0
  145. package/src/models/providers/openrouter.ts +24 -0
  146. package/src/models/providers/qwen-code.ts +33 -0
  147. package/src/models/providers/qwen.ts +34 -0
  148. package/src/models/providers/requesty.ts +23 -0
  149. package/src/models/providers/sambanova.ts +23 -0
  150. package/src/models/providers/sapaicore.ts +34 -0
  151. package/src/models/providers/together.ts +35 -0
  152. package/src/models/providers/vercel-ai-gateway.ts +23 -0
  153. package/src/models/providers/vertex.ts +36 -0
  154. package/src/models/providers/xai.ts +34 -0
  155. package/src/models/providers/zai.ts +25 -0
  156. package/src/models/query.ts +407 -0
  157. package/src/models/registry.ts +511 -0
  158. package/src/models/schemas/index.ts +62 -0
  159. package/src/models/schemas/model.ts +308 -0
  160. package/src/models/schemas/query.ts +336 -0
  161. package/src/providers/browser.ts +4 -0
  162. package/src/providers/handlers/ai-sdk-community.ts +226 -0
  163. package/src/providers/handlers/ai-sdk-provider-base.ts +193 -0
  164. package/src/providers/handlers/anthropic-base.ts +372 -0
  165. package/src/providers/handlers/asksage.test.ts +103 -0
  166. package/src/providers/handlers/asksage.ts +138 -0
  167. package/src/providers/handlers/auth.test.ts +19 -0
  168. package/src/providers/handlers/auth.ts +121 -0
  169. package/src/providers/handlers/base.test.ts +46 -0
  170. package/src/providers/handlers/base.ts +160 -0
  171. package/src/providers/handlers/bedrock-base.ts +390 -0
  172. package/src/providers/handlers/bedrock-client.ts +100 -0
  173. package/src/providers/handlers/codex.test.ts +123 -0
  174. package/src/providers/handlers/community-sdk.test.ts +288 -0
  175. package/src/providers/handlers/community-sdk.ts +392 -0
  176. package/src/providers/handlers/fetch-base.ts +68 -0
  177. package/src/providers/handlers/gemini-base.ts +302 -0
  178. package/src/providers/handlers/index.ts +67 -0
  179. package/src/providers/handlers/openai-base.ts +277 -0
  180. package/src/providers/handlers/openai-responses.ts +598 -0
  181. package/src/providers/handlers/providers.test.ts +120 -0
  182. package/src/providers/handlers/providers.ts +563 -0
  183. package/src/providers/handlers/r1-base.ts +280 -0
  184. package/src/providers/handlers/registry.ts +185 -0
  185. package/src/providers/handlers/vertex.test.ts +124 -0
  186. package/src/providers/handlers/vertex.ts +292 -0
  187. package/src/providers/index.ts +534 -0
  188. package/src/providers/public.browser.ts +20 -0
  189. package/src/providers/public.ts +51 -0
  190. package/src/providers/shared/openai-compatible.ts +63 -0
  191. package/src/providers/transform/ai-sdk-community-format.test.ts +73 -0
  192. package/src/providers/transform/ai-sdk-community-format.ts +115 -0
  193. package/src/providers/transform/anthropic-format.ts +218 -0
  194. package/src/providers/transform/content-format.ts +34 -0
  195. package/src/providers/transform/format-conversion.test.ts +310 -0
  196. package/src/providers/transform/gemini-format.ts +167 -0
  197. package/src/providers/transform/index.ts +22 -0
  198. package/src/providers/transform/openai-format.ts +247 -0
  199. package/src/providers/transform/r1-format.ts +287 -0
  200. package/src/providers/types/config.ts +388 -0
  201. package/src/providers/types/handler.ts +87 -0
  202. package/src/providers/types/index.ts +120 -0
  203. package/src/providers/types/messages.ts +158 -0
  204. package/src/providers/types/model-info.test.ts +57 -0
  205. package/src/providers/types/model-info.ts +65 -0
  206. package/src/providers/types/provider-ids.test.ts +12 -0
  207. package/src/providers/types/provider-ids.ts +89 -0
  208. package/src/providers/types/settings.test.ts +49 -0
  209. package/src/providers/types/settings.ts +533 -0
  210. package/src/providers/types/stream.ts +117 -0
  211. package/src/providers/utils/index.ts +27 -0
  212. package/src/providers/utils/retry.test.ts +140 -0
  213. package/src/providers/utils/retry.ts +188 -0
  214. package/src/providers/utils/stream-processor.test.ts +232 -0
  215. package/src/providers/utils/stream-processor.ts +472 -0
  216. package/src/providers/utils/tool-processor.test.ts +34 -0
  217. package/src/providers/utils/tool-processor.ts +111 -0
  218. package/src/sdk.ts +264 -0
  219. package/src/types.ts +79 -0
@@ -0,0 +1,407 @@
1
+ /**
2
+ * Model Query API
3
+ *
4
+ * High-level API for querying and filtering models across all providers.
5
+ * Uses the registry and schema validation for type-safe queries.
6
+ */
7
+
8
+ import { getAllModels, getModelsForProvider, getProviderIds } from "./registry";
9
+ import {
10
+ type ModelMatch,
11
+ type ModelQueryConfig,
12
+ ModelQueryConfigSchema,
13
+ matchesQuery,
14
+ sortModels,
15
+ } from "./schemas/index";
16
+
17
+ // =============================================================================
18
+ // Query Execution
19
+ // =============================================================================
20
+
21
+ /**
22
+ * Query models using a configuration object
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * // Get all models with image support
27
+ * const imageModels = queryModels({
28
+ * capabilities: ["images"],
29
+ * })
30
+ *
31
+ * // Get cheap reasoning models
32
+ * const cheapReasoning = queryModels({
33
+ * capabilities: ["reasoning"],
34
+ * maxInputPrice: 1,
35
+ * sortBy: "inputPrice",
36
+ * })
37
+ *
38
+ * // Get Anthropic and OpenAI models
39
+ * const models = queryModels({
40
+ * providers: ["anthropic", "openai"],
41
+ * includeDeprecated: false,
42
+ * })
43
+ * ```
44
+ */
45
+ export function queryModels(config: ModelQueryConfig): ModelMatch[] {
46
+ // Validate config
47
+ const validatedConfig = ModelQueryConfigSchema.parse(config);
48
+
49
+ // Determine which providers to search
50
+ const providerIds = validatedConfig.providers?.length
51
+ ? validatedConfig.providers.filter((id) => getProviderIds().includes(id))
52
+ : getProviderIds();
53
+
54
+ // Collect matching models
55
+ const matches: ModelMatch[] = [];
56
+
57
+ for (const providerId of providerIds) {
58
+ const models = getModelsForProvider(providerId);
59
+
60
+ for (const [modelId, info] of Object.entries(models)) {
61
+ if (matchesQuery(modelId, info, validatedConfig)) {
62
+ matches.push({ providerId, modelId, info });
63
+ }
64
+ }
65
+ }
66
+
67
+ // Sort results
68
+ const sorted = sortModels(
69
+ matches,
70
+ validatedConfig.sortBy,
71
+ validatedConfig.sortDirection ?? "asc",
72
+ );
73
+
74
+ // Apply limit
75
+ if (validatedConfig.limit && validatedConfig.limit > 0) {
76
+ return sorted.slice(0, validatedConfig.limit);
77
+ }
78
+
79
+ return sorted;
80
+ }
81
+
82
+ // =============================================================================
83
+ // Convenience Query Functions
84
+ // =============================================================================
85
+
86
+ /**
87
+ * Get all models with vision/image capabilities
88
+ */
89
+ export function getVisionModels(): ModelMatch[] {
90
+ return queryModels({ capabilities: ["images"] });
91
+ }
92
+
93
+ /**
94
+ * Get all models with reasoning/thinking capabilities
95
+ */
96
+ export function getReasoningModels(): ModelMatch[] {
97
+ return queryModels({ capabilities: ["reasoning"] });
98
+ }
99
+
100
+ /**
101
+ * Get all models with prompt caching support
102
+ */
103
+ export function getCachingModels(): ModelMatch[] {
104
+ return queryModels({ capabilities: ["prompt-cache"] });
105
+ }
106
+
107
+ /**
108
+ * Get all models with tool/function calling support
109
+ */
110
+ export function getToolModels(): ModelMatch[] {
111
+ return queryModels({ capabilities: ["tools"] });
112
+ }
113
+
114
+ /**
115
+ * Get all models supporting computer use
116
+ */
117
+ export function getComputerUseModels(): ModelMatch[] {
118
+ return queryModels({ capabilities: ["computer-use"] });
119
+ }
120
+
121
+ /**
122
+ * Get all active (non-deprecated) models
123
+ */
124
+ export function getActiveModels(): ModelMatch[] {
125
+ return queryModels({
126
+ includeDeprecated: false,
127
+ status: ["active", "preview"],
128
+ });
129
+ }
130
+
131
+ /**
132
+ * Get all deprecated models
133
+ */
134
+ export function getDeprecatedModels(): ModelMatch[] {
135
+ return queryModels({
136
+ includeDeprecated: true,
137
+ status: ["deprecated"],
138
+ });
139
+ }
140
+
141
+ /**
142
+ * Get models within a price range (input price per million tokens)
143
+ */
144
+ export function getModelsInPriceRange(
145
+ maxInputPrice: number,
146
+ maxOutputPrice?: number,
147
+ ): ModelMatch[] {
148
+ return queryModels({
149
+ maxInputPrice,
150
+ maxOutputPrice,
151
+ sortBy: "inputPrice",
152
+ });
153
+ }
154
+
155
+ /**
156
+ * Get models with minimum context window size
157
+ */
158
+ export function getModelsWithContextWindow(minTokens: number): ModelMatch[] {
159
+ return queryModels({
160
+ minContextWindow: minTokens,
161
+ sortBy: "contextWindow",
162
+ sortDirection: "desc",
163
+ });
164
+ }
165
+
166
+ /**
167
+ * Get models by provider
168
+ */
169
+ export function getModelsByProvider(providerId: string): ModelMatch[] {
170
+ return queryModels({ providers: [providerId] });
171
+ }
172
+
173
+ /**
174
+ * Search models by name or ID
175
+ */
176
+ export function searchModels(searchTerm: string): ModelMatch[] {
177
+ return queryModels({ search: searchTerm });
178
+ }
179
+
180
+ // =============================================================================
181
+ // Query Builder (Fluent API)
182
+ // =============================================================================
183
+
184
+ /**
185
+ * Fluent query builder for constructing model queries
186
+ *
187
+ * @example
188
+ * ```typescript
189
+ * const models = createQuery()
190
+ * .fromProviders(["anthropic", "openai"])
191
+ * .withCapabilities(["images", "reasoning"])
192
+ * .maxPrice({ input: 5 })
193
+ * .sortBy("inputPrice")
194
+ * .limit(10)
195
+ * .execute()
196
+ * ```
197
+ */
198
+ export class ModelQueryBuilder {
199
+ private config: ModelQueryConfig = {};
200
+
201
+ /**
202
+ * Filter by provider IDs
203
+ */
204
+ fromProviders(providers: string[]): this {
205
+ this.config.providers = providers;
206
+ return this;
207
+ }
208
+
209
+ /**
210
+ * Require all specified capabilities
211
+ */
212
+ withCapabilities(capabilities: ModelQueryConfig["capabilities"]): this {
213
+ this.config.capabilities = capabilities;
214
+ return this;
215
+ }
216
+
217
+ /**
218
+ * Require at least one of the specified capabilities
219
+ */
220
+ withAnyCapabilities(capabilities: ModelQueryConfig["anyCapabilities"]): this {
221
+ this.config.anyCapabilities = capabilities;
222
+ return this;
223
+ }
224
+
225
+ /**
226
+ * Exclude models with specified capabilities
227
+ */
228
+ excludeCapabilities(
229
+ capabilities: ModelQueryConfig["excludeCapabilities"],
230
+ ): this {
231
+ this.config.excludeCapabilities = capabilities;
232
+ return this;
233
+ }
234
+
235
+ /**
236
+ * Filter by model status
237
+ */
238
+ withStatus(status: ModelQueryConfig["status"]): this {
239
+ this.config.status = status;
240
+ return this;
241
+ }
242
+
243
+ /**
244
+ * Include deprecated models
245
+ */
246
+ includeDeprecated(include = true): this {
247
+ this.config.includeDeprecated = include;
248
+ return this;
249
+ }
250
+
251
+ /**
252
+ * Filter by API format
253
+ */
254
+ withApiFormat(format: ModelQueryConfig["apiFormat"]): this {
255
+ this.config.apiFormat = format;
256
+ return this;
257
+ }
258
+
259
+ /**
260
+ * Filter by context window size
261
+ */
262
+ contextWindow(options: { min?: number; max?: number }): this {
263
+ if (options.min !== undefined) {
264
+ this.config.minContextWindow = options.min;
265
+ }
266
+ if (options.max !== undefined) {
267
+ this.config.maxContextWindow = options.max;
268
+ }
269
+ return this;
270
+ }
271
+
272
+ /**
273
+ * Filter by minimum output tokens
274
+ */
275
+ minMaxTokens(tokens: number): this {
276
+ this.config.minMaxTokens = tokens;
277
+ return this;
278
+ }
279
+
280
+ /**
281
+ * Filter by maximum price
282
+ */
283
+ maxPrice(options: { input?: number; output?: number }): this {
284
+ if (options.input !== undefined) {
285
+ this.config.maxInputPrice = options.input;
286
+ }
287
+ if (options.output !== undefined) {
288
+ this.config.maxOutputPrice = options.output;
289
+ }
290
+ return this;
291
+ }
292
+
293
+ /**
294
+ * Search by name or ID
295
+ */
296
+ search(term: string): this {
297
+ this.config.search = term;
298
+ return this;
299
+ }
300
+
301
+ /**
302
+ * Filter by thinking/reasoning support
303
+ */
304
+ hasThinking(has = true): this {
305
+ this.config.hasThinking = has;
306
+ return this;
307
+ }
308
+
309
+ /**
310
+ * Sort results
311
+ */
312
+ sortBy(
313
+ field: ModelQueryConfig["sortBy"],
314
+ direction: ModelQueryConfig["sortDirection"] = "asc",
315
+ ): this {
316
+ this.config.sortBy = field;
317
+ this.config.sortDirection = direction;
318
+ return this;
319
+ }
320
+
321
+ /**
322
+ * Limit number of results
323
+ */
324
+ limit(count: number): this {
325
+ this.config.limit = count;
326
+ return this;
327
+ }
328
+
329
+ /**
330
+ * Get the current config
331
+ */
332
+ getConfig(): ModelQueryConfig {
333
+ return { ...this.config };
334
+ }
335
+
336
+ /**
337
+ * Execute the query
338
+ */
339
+ execute(): ModelMatch[] {
340
+ return queryModels(this.config);
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Create a new query builder
346
+ */
347
+ export function createQuery(): ModelQueryBuilder {
348
+ return new ModelQueryBuilder();
349
+ }
350
+
351
+ // =============================================================================
352
+ // Statistics
353
+ // =============================================================================
354
+
355
+ /**
356
+ * Get statistics about registered models
357
+ */
358
+ export async function getModelStatistics(): Promise<{
359
+ totalModels: number;
360
+ modelsByProvider: Record<string, number>;
361
+ modelsByCapability: Record<string, number>;
362
+ modelsByStatus: Record<string, number>;
363
+ priceRange: { min: number; max: number; avg: number };
364
+ }> {
365
+ const allModels = await getAllModels();
366
+
367
+ const modelsByProvider: Record<string, number> = {};
368
+ const modelsByCapability: Record<string, number> = {};
369
+ const modelsByStatus: Record<string, number> = {};
370
+ const prices: number[] = [];
371
+
372
+ for (const { providerId, info } of allModels) {
373
+ // Count by provider
374
+ modelsByProvider[providerId] = (modelsByProvider[providerId] ?? 0) + 1;
375
+
376
+ // Count by capability
377
+ for (const cap of info.capabilities ?? []) {
378
+ modelsByCapability[cap] = (modelsByCapability[cap] ?? 0) + 1;
379
+ }
380
+
381
+ // Count by status
382
+ const status = info.status ?? "active";
383
+ modelsByStatus[status] = (modelsByStatus[status] ?? 0) + 1;
384
+
385
+ // Collect prices
386
+ if (info.pricing?.input !== undefined) {
387
+ prices.push(info.pricing.input);
388
+ }
389
+ }
390
+
391
+ // Calculate price statistics
392
+ const sortedPrices = prices.sort((a, b) => a - b);
393
+ const priceRange = {
394
+ min: sortedPrices[0] ?? 0,
395
+ max: sortedPrices[sortedPrices.length - 1] ?? 0,
396
+ avg:
397
+ prices.length > 0 ? prices.reduce((a, b) => a + b, 0) / prices.length : 0,
398
+ };
399
+
400
+ return {
401
+ totalModels: allModels.length,
402
+ modelsByProvider,
403
+ modelsByCapability,
404
+ modelsByStatus,
405
+ priceRange,
406
+ };
407
+ }