Chris Estreich 4 недель назад
Родитель
Сommit
6bdefb8de3
1 измененных файлов с 35 добавлено и 28 удалено
  1. 35 28
      src/api/providers/fetchers/chutes.ts

+ 35 - 28
src/api/providers/fetchers/chutes.ts

@@ -1,19 +1,19 @@
 import axios from "axios"
 import { z } from "zod"
 
-import { type ModelInfo, TOOL_PROTOCOL, chutesModels } from "@roo-code/types"
+import { type ModelInfo, chutesModels } from "@roo-code/types"
 
 import { DEFAULT_HEADERS } from "../constants"
 
-// Chutes models endpoint follows OpenAI /models shape with additional fields
+// Chutes models endpoint follows OpenAI /models shape with additional fields.
 const ChutesModelSchema = z.object({
 	id: z.string(),
 	object: z.literal("model").optional(),
 	owned_by: z.string().optional(),
 	created: z.number().optional(),
-	context_length: z.number(),
+	context_length: z.number().optional(),
 	max_model_len: z.number(),
-	input_modalities: z.array(z.string()),
+	input_modalities: z.array(z.string()).optional(),
 	supported_features: z.array(z.string()).optional(),
 })
 
@@ -21,42 +21,49 @@ const ChutesModelsResponseSchema = z.object({ data: z.array(ChutesModelSchema) }
 
 export async function getChutesModels(apiKey?: string): Promise<Record<string, ModelInfo>> {
 	const headers: Record<string, string> = { ...DEFAULT_HEADERS }
-	if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`
+
+	if (apiKey) {
+		headers["Authorization"] = `Bearer ${apiKey}`
+	}
 
 	const url = "https://llm.chutes.ai/v1/models"
 
-	// Start with hardcoded models as the base
+	// Start with hardcoded models as the base.
 	const models: Record<string, ModelInfo> = { ...chutesModels }
 
 	try {
 		const response = await axios.get(url, { headers })
 		const parsed = ChutesModelsResponseSchema.safeParse(response.data)
-		const data = parsed.success ? parsed.data.data : response.data?.data || []
-
-		for (const m of data as Array<z.infer<typeof ChutesModelSchema>>) {
-			// Extract from API response (all fields are required)
-			const contextWindow = m.context_length
-			const maxTokens = m.max_model_len
-			const supportsImages = m.input_modalities.includes("image")
-			const supportsNativeTools = m.supported_features?.includes("tools") ?? false
-
-			const info: ModelInfo = {
-				maxTokens,
-				contextWindow,
-				supportsImages,
-				supportsPromptCache: false,
-				supportsNativeTools,
-				inputPrice: 0,
-				outputPrice: 0,
-				description: `Chutes AI model: ${m.id}`,
-			}
 
-			// Union: dynamic models override hardcoded ones if they have the same ID
-			models[m.id] = info
+		if (parsed.success) {
+			for (const m of parsed.data.data) {
+				const contextWindow = m.context_length
+
+				if (!contextWindow) {
+					console.error(`Context length is required for Chutes model: ${m.id}`)
+					continue
+				}
+
+				const info: ModelInfo = {
+					maxTokens: m.max_model_len,
+					contextWindow,
+					supportsImages: (m.input_modalities || []).includes("image"),
+					supportsPromptCache: false,
+					supportsNativeTools: (m.supported_features || []).includes("tools"),
+					inputPrice: 0,
+					outputPrice: 0,
+					description: `Chutes AI model: ${m.id}`,
+				}
+
+				// Union: dynamic models override hardcoded ones if they have the same ID.
+				models[m.id] = info
+			}
+		} else {
+			console.error(`Error parsing Chutes models: ${JSON.stringify(parsed.error.format(), null, 2)}`)
 		}
 	} catch (error) {
 		console.error(`Error fetching Chutes models: ${error instanceof Error ? error.message : String(error)}`)
-		// On error, still return hardcoded models
+		// On error, still return hardcoded models.
 	}
 
 	return models