fix(core): expose models.dev modes as models (#34714)
This commit is contained in:
parent
2324a63fc6
commit
f8626865b9
2 changed files with 203 additions and 54 deletions
|
|
@ -11,7 +11,7 @@ function released(date: string) {
|
|||
return Number.isFinite(time) ? time : 0
|
||||
}
|
||||
|
||||
function cost(input: ModelsDev.Model["cost"]) {
|
||||
function cost(input: ModelsDev.Model["cost"]): ModelV2Info["cost"] {
|
||||
const base = {
|
||||
input: input?.input ?? 0,
|
||||
output: input?.output ?? 0,
|
||||
|
|
@ -20,25 +20,57 @@ function cost(input: ModelsDev.Model["cost"]) {
|
|||
write: input?.cache_write ?? 0,
|
||||
},
|
||||
}
|
||||
if (!input?.context_over_200k) return [base]
|
||||
return [
|
||||
base,
|
||||
{
|
||||
tier: {
|
||||
type: "context" as const,
|
||||
size: 200_000,
|
||||
},
|
||||
input: input.context_over_200k.input,
|
||||
output: input.context_over_200k.output,
|
||||
...(input?.tiers?.map((item) => ({
|
||||
tier: item.tier,
|
||||
input: item.input,
|
||||
output: item.output,
|
||||
cache: {
|
||||
read: input.context_over_200k.cache_read ?? 0,
|
||||
write: input.context_over_200k.cache_write ?? 0,
|
||||
read: item.cache_read ?? 0,
|
||||
write: item.cache_write ?? 0,
|
||||
},
|
||||
},
|
||||
})) ?? []),
|
||||
...(input?.context_over_200k
|
||||
? [
|
||||
{
|
||||
tier: {
|
||||
type: "context" as const,
|
||||
size: 200_000,
|
||||
},
|
||||
input: input.context_over_200k.input,
|
||||
output: input.context_over_200k.output,
|
||||
cache: {
|
||||
read: input.context_over_200k.cache_read ?? 0,
|
||||
write: input.context_over_200k.cache_write ?? 0,
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
]
|
||||
}
|
||||
|
||||
function variants(model: ModelsDev.Model, packageName: string | undefined): ModelV2Info["variants"] {
|
||||
function mergeCost(base: ModelV2Info["cost"], override: ModelsDev.Model["cost"] | undefined) {
|
||||
if (!override) return base
|
||||
const next = cost(override)
|
||||
const [baseDefault, ...baseTiers] = base
|
||||
const [nextDefault, ...nextTiers] = next
|
||||
const tierKey = (item: ModelV2Info["cost"][number]) => `${item.tier?.type ?? "base"}:${item.tier?.size ?? 0}`
|
||||
const merge = (left: ModelV2Info["cost"][number], right: ModelV2Info["cost"][number]) => ({
|
||||
...left,
|
||||
...right,
|
||||
tier: right.tier ?? left.tier,
|
||||
cache: { ...left.cache, ...right.cache },
|
||||
})
|
||||
const tiers = new Map(baseTiers.map((item) => [tierKey(item), item]))
|
||||
for (const item of nextTiers) {
|
||||
const current = tiers.get(tierKey(item))
|
||||
tiers.set(tierKey(item), current ? merge(current, item) : item)
|
||||
}
|
||||
return [merge(baseDefault ?? { input: 0, output: 0, cache: { read: 0, write: 0 } }, nextDefault), ...tiers.values()]
|
||||
}
|
||||
|
||||
function reasoningVariants(model: ModelsDev.Model, packageName: string | undefined): ModelV2Info["variants"] {
|
||||
const result = new Map<ModelV2.VariantID, ModelV2Info["variants"][number]>()
|
||||
if (packageName === "@ai-sdk/openai" || packageName === "@ai-sdk/openai-compatible") {
|
||||
const option = model.reasoning_options?.find((option) => option.type === "effort")
|
||||
|
|
@ -56,17 +88,13 @@ function variants(model: ModelsDev.Model, packageName: string | undefined): Mode
|
|||
})
|
||||
}
|
||||
}
|
||||
for (const [id, item] of Object.entries(model.experimental?.modes ?? {})) {
|
||||
const variantID = ModelV2.VariantID.make(id)
|
||||
result.set(variantID, {
|
||||
id: variantID,
|
||||
headers: { ...(item.provider?.headers ?? {}) },
|
||||
body: { ...(item.provider?.body ?? {}) },
|
||||
})
|
||||
}
|
||||
return [...result.values()]
|
||||
}
|
||||
|
||||
function modeName(model: ModelsDev.Model, mode: string) {
|
||||
return `${model.name} ${mode.charAt(0).toUpperCase()}${mode.slice(1)}`
|
||||
}
|
||||
|
||||
function mergeVariants(model: ModelV2Info, next: ModelV2Info["variants"]) {
|
||||
const existing = new Map(model.variants.map((variant) => [variant.id, variant]))
|
||||
const nextIDs = new Set(next.map((variant) => variant.id))
|
||||
|
|
@ -76,6 +104,50 @@ function mergeVariants(model: ModelV2Info, next: ModelV2Info["variants"]) {
|
|||
]
|
||||
}
|
||||
|
||||
function applyModel(
|
||||
draft: ModelV2Info,
|
||||
model: ModelsDev.Model,
|
||||
input: {
|
||||
readonly name?: string
|
||||
readonly cost?: ModelV2Info["cost"]
|
||||
readonly request?: NonNullable<NonNullable<ModelsDev.Model["experimental"]>["modes"]>[string]["provider"]
|
||||
readonly variants?: ModelV2Info["variants"]
|
||||
} = {},
|
||||
) {
|
||||
draft.name = input.name ?? model.name
|
||||
draft.family = model.family ? ModelV2.Family.make(model.family) : undefined
|
||||
draft.api = model.provider?.npm
|
||||
? {
|
||||
id: ModelV2.ID.make(model.id),
|
||||
type: "aisdk",
|
||||
package: model.provider.npm,
|
||||
url: model.provider.api,
|
||||
}
|
||||
: {
|
||||
id: ModelV2.ID.make(model.id),
|
||||
type: "native",
|
||||
url: model.provider?.api,
|
||||
settings: {},
|
||||
}
|
||||
draft.capabilities = {
|
||||
tools: model.tool_call,
|
||||
input: [...(model.modalities?.input ?? [])],
|
||||
output: [...(model.modalities?.output ?? [])],
|
||||
}
|
||||
mergeVariants(draft, input.variants ?? [])
|
||||
draft.time.released = released(model.release_date)
|
||||
draft.cost = input.cost ?? cost(model.cost)
|
||||
draft.status = model.status ?? "active"
|
||||
draft.enabled = true
|
||||
draft.limit = {
|
||||
context: model.limit.context,
|
||||
input: model.limit.input,
|
||||
output: model.limit.output,
|
||||
}
|
||||
Object.assign(draft.request.headers, input.request?.headers ?? {})
|
||||
Object.assign(draft.request.body, input.request?.body ?? {})
|
||||
}
|
||||
|
||||
export const ModelsDevPlugin = define({
|
||||
id: "models-dev",
|
||||
effect: Effect.fn(function* (ctx) {
|
||||
|
|
@ -120,39 +192,19 @@ export const ModelsDevPlugin = define({
|
|||
})
|
||||
|
||||
for (const model of Object.values(item.models)) {
|
||||
const modelID = ModelV2.ID.make(model.id)
|
||||
catalog.model.update(providerID, modelID, (draft) => {
|
||||
draft.name = model.name
|
||||
draft.family = model.family ? ModelV2.Family.make(model.family) : undefined
|
||||
draft.api = model.provider?.npm
|
||||
? {
|
||||
id: draft.api.id,
|
||||
type: "aisdk",
|
||||
package: model.provider?.npm,
|
||||
url: model.provider.api,
|
||||
}
|
||||
: {
|
||||
id: draft.api.id,
|
||||
type: "native",
|
||||
url: model.provider?.api,
|
||||
settings: {},
|
||||
}
|
||||
draft.capabilities = {
|
||||
tools: model.tool_call,
|
||||
input: [...(model.modalities?.input ?? [])],
|
||||
output: [...(model.modalities?.output ?? [])],
|
||||
}
|
||||
mergeVariants(draft, variants(model, model.provider?.npm ?? item.npm))
|
||||
draft.time.released = released(model.release_date)
|
||||
draft.cost = cost(model.cost)
|
||||
draft.status = model.status ?? "active"
|
||||
draft.enabled = true
|
||||
draft.limit = {
|
||||
context: model.limit.context,
|
||||
input: model.limit.input,
|
||||
output: model.limit.output,
|
||||
}
|
||||
})
|
||||
const baseCost = cost(model.cost)
|
||||
const variants = reasoningVariants(model, model.provider?.npm ?? item.npm)
|
||||
catalog.model.update(providerID, model.id, (draft) => applyModel(draft, model, { cost: baseCost, variants }))
|
||||
for (const [mode, options] of Object.entries(model.experimental?.modes ?? {})) {
|
||||
catalog.model.update(providerID, `${model.id}-${mode}`, (draft) =>
|
||||
applyModel(draft, model, {
|
||||
name: modeName(model, mode),
|
||||
cost: mergeCost(baseCost, options.cost),
|
||||
request: options.provider,
|
||||
variants,
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue