Skip to content

Commit 0e2d9bb

Browse files
committed
Fix chutes model fetching
1 parent a3de293 commit 0e2d9bb

File tree

1 file changed

+35
-28
lines changed

1 file changed

+35
-28
lines changed

src/api/providers/fetchers/chutes.ts

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,69 @@
11
import axios from "axios"
22
import { z } from "zod"
33

4-
import { type ModelInfo, TOOL_PROTOCOL, chutesModels } from "@roo-code/types"
4+
import { type ModelInfo, chutesModels } from "@roo-code/types"
55

66
import { DEFAULT_HEADERS } from "../constants"
77

8-
// Chutes models endpoint follows OpenAI /models shape with additional fields
8+
// Chutes models endpoint follows OpenAI /models shape with additional fields.
99
const ChutesModelSchema = z.object({
1010
id: z.string(),
1111
object: z.literal("model").optional(),
1212
owned_by: z.string().optional(),
1313
created: z.number().optional(),
14-
context_length: z.number(),
14+
context_length: z.number().optional(),
1515
max_model_len: z.number(),
16-
input_modalities: z.array(z.string()),
16+
input_modalities: z.array(z.string()).optional(),
1717
supported_features: z.array(z.string()).optional(),
1818
})
1919

2020
const ChutesModelsResponseSchema = z.object({ data: z.array(ChutesModelSchema) })
2121

2222
export async function getChutesModels(apiKey?: string): Promise<Record<string, ModelInfo>> {
2323
const headers: Record<string, string> = { ...DEFAULT_HEADERS }
24-
if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`
24+
25+
if (apiKey) {
26+
headers["Authorization"] = `Bearer ${apiKey}`
27+
}
2528

2629
const url = "https://llm.chutes.ai/v1/models"
2730

28-
// Start with hardcoded models as the base
31+
// Start with hardcoded models as the base.
2932
const models: Record<string, ModelInfo> = { ...chutesModels }
3033

3134
try {
3235
const response = await axios.get(url, { headers })
3336
const parsed = ChutesModelsResponseSchema.safeParse(response.data)
34-
const data = parsed.success ? parsed.data.data : response.data?.data || []
35-
36-
for (const m of data as Array<z.infer<typeof ChutesModelSchema>>) {
37-
// Extract from API response (all fields are required)
38-
const contextWindow = m.context_length
39-
const maxTokens = m.max_model_len
40-
const supportsImages = m.input_modalities.includes("image")
41-
const supportsNativeTools = m.supported_features?.includes("tools") ?? false
42-
43-
const info: ModelInfo = {
44-
maxTokens,
45-
contextWindow,
46-
supportsImages,
47-
supportsPromptCache: false,
48-
supportsNativeTools,
49-
inputPrice: 0,
50-
outputPrice: 0,
51-
description: `Chutes AI model: ${m.id}`,
52-
}
5337

54-
// Union: dynamic models override hardcoded ones if they have the same ID
55-
models[m.id] = info
38+
if (parsed.success) {
39+
for (const m of parsed.data.data) {
40+
const contextWindow = m.context_length
41+
42+
if (!contextWindow) {
43+
console.error(`Context length is required for Chutes model: ${m.id}`)
44+
continue
45+
}
46+
47+
const info: ModelInfo = {
48+
maxTokens: m.max_model_len,
49+
contextWindow,
50+
supportsImages: (m.input_modalities || []).includes("image"),
51+
supportsPromptCache: false,
52+
supportsNativeTools: (m.supported_features || []).includes("tools"),
53+
inputPrice: 0,
54+
outputPrice: 0,
55+
description: `Chutes AI model: ${m.id}`,
56+
}
57+
58+
// Union: dynamic models override hardcoded ones if they have the same ID.
59+
models[m.id] = info
60+
}
61+
} else {
62+
console.error(`Error parsing Chutes models: ${JSON.stringify(parsed.error.format(), null, 2)}`)
5663
}
5764
} catch (error) {
5865
console.error(`Error fetching Chutes models: ${error instanceof Error ? error.message : String(error)}`)
59-
// On error, still return hardcoded models
66+
// On error, still return hardcoded models.
6067
}
6168

6269
return models

0 commit comments

Comments
 (0)