|
1 | 1 | import axios from "axios" |
2 | 2 |
|
| 3 | +import { RooModelsResponseSchema } from "@roo-code/types" |
| 4 | + |
3 | 5 | import type { ModelRecord } from "../../../shared/api" |
4 | 6 |
|
5 | 7 | import { DEFAULT_HEADERS } from "../constants" |
@@ -37,49 +39,52 @@ export async function getRooModels(baseUrl: string, apiKey?: string): Promise<Mo |
37 | 39 | // Added timeout to prevent indefinite hanging |
38 | 40 | const response = await axios.get(url, { headers, timeout: 10000 }) |
39 | 41 | const models: ModelRecord = {} |
40 | | - // Process the model info from the response |
41 | | - // Expected format: { object: "list", data: [{ id, name, description, context_window, max_tokens, tags, pricing }] } |
42 | | - if (response.data && response.data.data && Array.isArray(response.data.data)) { |
43 | | - for (const model of response.data.data) { |
44 | | - const modelId = model.id |
45 | | - |
46 | | - if (!modelId) continue |
47 | | - |
48 | | - // Extract model data from the API response |
49 | | - const contextWindow = model.context_window || 262_144 |
50 | | - const maxTokens = model.max_tokens || 16_384 |
51 | | - const tags = model.tags || [] |
52 | | - const pricing = model.pricing || {} |
53 | | - |
54 | | - // Determine if the model supports images based on tags |
55 | | - const supportsImages = tags.includes("vision") || tags.includes("image") |
56 | | - |
57 | | - // Parse pricing (API returns strings, convert to numbers) |
58 | | - // Handle both direct pricing and cache pricing if available |
59 | | - const inputPrice = pricing.input ? parseFloat(pricing.input) : 0 |
60 | | - const outputPrice = pricing.output ? parseFloat(pricing.output) : 0 |
61 | | - const cacheReadPrice = pricing.input_cache_read ? parseFloat(pricing.input_cache_read) : undefined |
62 | | - const cacheWritePrice = pricing.input_cache_write ? parseFloat(pricing.input_cache_write) : undefined |
63 | | - |
64 | | - models[modelId] = { |
65 | | - maxTokens, |
66 | | - contextWindow, |
67 | | - supportsImages, |
68 | | - supportsPromptCache: Boolean(cacheReadPrice !== undefined || cacheWritePrice !== undefined), |
69 | | - inputPrice, |
70 | | - outputPrice, |
71 | | - cacheWritesPrice: cacheWritePrice, |
72 | | - cacheReadsPrice: cacheReadPrice, |
73 | | - description: model.description || model.name || `Model available through Roo Code Cloud`, |
74 | | - deprecated: model.deprecated || false, |
75 | | - } |
76 | | - } |
77 | | - } else { |
78 | | - // If response.data.data is not in the expected format, consider it an error. |
| 42 | + |
| 43 | + // Validate response against schema |
| 44 | + const parsed = RooModelsResponseSchema.safeParse(response.data) |
| 45 | + |
| 46 | + if (!parsed.success) { |
79 | 47 | console.error("Error fetching Roo Code Cloud models: Unexpected response format", response.data) |
| 48 | + console.error("Validation errors:", parsed.error.format()) |
80 | 49 | throw new Error("Failed to fetch Roo Code Cloud models: Unexpected response format.") |
81 | 50 | } |
82 | 51 |
|
| 52 | + // Process the validated model data |
| 53 | + for (const model of parsed.data.data) { |
| 54 | + const modelId = model.id |
| 55 | + |
| 56 | + if (!modelId) continue |
| 57 | + |
| 58 | + // Extract model data from the validated API response |
| 59 | + // All required fields are guaranteed by the schema |
| 60 | + const contextWindow = model.context_window |
| 61 | + const maxTokens = model.max_tokens |
| 62 | + const tags = model.tags || [] |
| 63 | + const pricing = model.pricing |
| 64 | + |
| 65 | + // Determine if the model supports images based on tags |
| 66 | + const supportsImages = tags.includes("vision") |
| 67 | + |
| 68 | + // Parse pricing (API returns strings, convert to numbers) |
| 69 | + const inputPrice = parseFloat(pricing.input) |
| 70 | + const outputPrice = parseFloat(pricing.output) |
| 71 | + const cacheReadPrice = pricing.input_cache_read ? parseFloat(pricing.input_cache_read) : undefined |
| 72 | + const cacheWritePrice = pricing.input_cache_write ? parseFloat(pricing.input_cache_write) : undefined |
| 73 | + |
| 74 | + models[modelId] = { |
| 75 | + maxTokens, |
| 76 | + contextWindow, |
| 77 | + supportsImages, |
| 78 | + supportsPromptCache: Boolean(cacheReadPrice !== undefined), |
| 79 | + inputPrice, |
| 80 | + outputPrice, |
| 81 | + cacheWritesPrice: cacheWritePrice, |
| 82 | + cacheReadsPrice: cacheReadPrice, |
| 83 | + description: model.description || model.name, |
| 84 | + deprecated: model.deprecated || false, |
| 85 | + } |
| 86 | + } |
| 87 | + |
83 | 88 | return models |
84 | 89 | } catch (error: any) { |
85 | 90 | console.error("Error fetching Roo Code Cloud models:", error.message ? error.message : error) |
|
0 commit comments