feat(core): support response-shaped catalog models

This commit is contained in:
Jack 2026-08-01 14:50:00 +08:00
commit e660539462
42 changed files with 144 additions and 75 deletions

View file

@ -115,7 +115,11 @@ export const Model = Schema.Struct({
),
status: Schema.optional(CatalogModelStatus),
provider: Schema.optional(
Schema.Struct({ npm: Schema.optional(Schema.String), api: Schema.optional(Schema.String) }),
Schema.Struct({
npm: Schema.optional(Schema.String),
api: Schema.optional(Schema.String),
shape: Schema.optional(Schema.Literals(["responses", "completions"])),
}),
),
})
export type Model = Schema.Schema.Type<typeof Model>

View file

@ -84,19 +84,27 @@ function applyModel(
) {
draft.name = input.name ?? model.name
draft.family = model.family
draft.api = model.provider?.npm
? {
id: model.id,
type: "aisdk",
package: model.provider.npm,
url: model.provider.api,
}
: {
id: model.id,
type: "native",
url: model.provider?.api,
settings: {},
}
draft.api =
model.provider?.shape === "responses"
? {
id: model.id,
type: "aisdk",
package: "@ai-sdk/openai",
url: model.provider.api ?? draft.api.url,
}
: model.provider?.npm
? {
id: model.id,
type: "aisdk",
package: model.provider.npm,
url: model.provider.api,
}
: {
id: model.id,
type: "native",
url: model.provider?.api,
settings: {},
}
draft.capabilities = {
tools: model.tool_call,
input: [...(model.modalities?.input ?? [])],

View file

@ -62,7 +62,11 @@ export const Model = Schema.Struct({
experimental: Schema.optional(Schema.Boolean),
status: Schema.optional(ModelStatus),
provider: Schema.optional(
Schema.Struct({ npm: Schema.optional(Schema.String), api: Schema.optional(Schema.String) }),
Schema.Struct({
npm: Schema.optional(Schema.String),
api: Schema.optional(Schema.String),
shape: Schema.optional(Schema.Literals(["responses", "completions"])),
}),
),
options: Schema.optional(Schema.Record(Schema.String, Schema.Any)),
headers: Schema.optional(Schema.Record(Schema.String, Schema.String)),

View file

@ -76,6 +76,17 @@ describe("ModelsDevPlugin", () => {
},
},
},
"deepseek-v4-flash": {
id: "deepseek-v4-flash",
name: "DeepSeek V4 Flash",
release_date: "2026-07-31",
attachment: false,
reasoning: true,
temperature: true,
tool_call: true,
provider: { shape: "responses" },
limit: { context: 1_000_000, output: 384_000 },
},
},
},
} satisfies Record<string, ModelsDev.Provider>),
@ -92,6 +103,7 @@ describe("ModelsDevPlugin", () => {
const providerID = ProviderV2.ID.make("acme")
const base = yield* catalog.model.get(providerID, ModelV2.ID.make("gpt-5.4"))
const fast = yield* catalog.model.get(providerID, ModelV2.ID.make("gpt-5.4-fast"))
const deepseek = yield* catalog.model.get(providerID, ModelV2.ID.make("deepseek-v4-flash"))
expect(base?.variants).toEqual([])
expect(base?.request.body).toEqual({})
@ -121,6 +133,12 @@ describe("ModelsDevPlugin", () => {
cache: { read: 0.5, write: 0 },
},
])
expect(deepseek?.api).toMatchObject({
id: "deepseek-v4-flash",
type: "aisdk",
package: "@ai-sdk/openai",
url: "https://api.acme.test/v1",
})
}),
)