Skip to content

Commit 9e8bab3

Browse files
fix(zoo-gateway): accept models list without created/description fields
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 2bc6f5a commit 9e8bab3

2 files changed

Lines changed: 35 additions & 3 deletions

File tree

src/api/providers/fetchers/__tests__/zoo-gateway.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,37 @@ describe("Zoo Gateway Fetchers", () => {
104104
consoleErrorSpy.mockRestore()
105105
})
106106

107+
it("accepts gateway catalog models without created or description (e.g. Bedrock)", async () => {
108+
mockedAxios.get.mockResolvedValueOnce({
109+
data: {
110+
object: "list",
111+
data: [
112+
{
113+
id: "anthropic/claude-sonnet-4",
114+
object: "model",
115+
owned_by: "anthropic",
116+
name: "Claude Sonnet 4",
117+
context_window: 200000,
118+
max_tokens: 64000,
119+
type: "language",
120+
pricing: {
121+
input: "3.00",
122+
output: "15.00",
123+
},
124+
},
125+
],
126+
},
127+
})
128+
129+
const models = await getZooGatewayModels({
130+
zooGatewayBaseUrl: baseUrl,
131+
zooSessionToken: token,
132+
} as any)
133+
134+
expect(Object.keys(models)).toEqual(["anthropic/claude-sonnet-4"])
135+
expect(models["anthropic/claude-sonnet-4"].description).toBe("Claude Sonnet 4")
136+
})
137+
107138
it("returns {} on a structurally broken response instead of throwing", async () => {
108139
const consoleErrorSpy = vitest.spyOn(console, "error").mockImplementation(() => {})
109140
mockedAxios.get.mockResolvedValueOnce({ data: { unexpected: true } })

src/api/providers/fetchers/vercel-ai-gateway.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ const vercelAiGatewayPricingSchema = z.object({
2626
const vercelAiGatewayModelSchema = z.object({
2727
id: z.string(),
2828
object: z.string(),
29-
created: z.number(),
29+
// Zoo Gateway / Bedrock catalog entries omit these; they are not used for routing.
30+
created: z.number().optional(),
3031
owned_by: z.string(),
3132
name: z.string(),
32-
description: z.string(),
33+
description: z.string().optional(),
3334
context_window: z.number(),
3435
max_tokens: z.number(),
3536
type: z.string(),
@@ -110,7 +111,7 @@ export const parseVercelAiGatewayModel = ({ id, model }: { id: string; model: Ve
110111
outputPrice: parseApiPrice(model.pricing?.output),
111112
cacheWritesPrice,
112113
cacheReadsPrice,
113-
description: model.description,
114+
description: model.description ?? model.name,
114115
}
115116

116117
return modelInfo

0 commit comments

Comments
 (0)