fix(core): derive reasoning variants from models.dev
This commit is contained in:
@@ -38,12 +38,33 @@ function cost(input: ModelsDev.Model["cost"]) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
function variants(model: ModelsDev.Model) {
|
function variants(model: ModelsDev.Model, packageName: string | undefined): ModelV2Info["variants"] {
|
||||||
return Object.entries(model.experimental?.modes ?? {}).map(([id, item]) => ({
|
const result = new Map<ModelV2.VariantID, ModelV2Info["variants"][number]>()
|
||||||
id: ModelV2.VariantID.make(id),
|
if (packageName === "@ai-sdk/openai" || packageName === "@ai-sdk/openai-compatible") {
|
||||||
headers: { ...(item.provider?.headers ?? {}) },
|
const option = model.reasoning_options?.find((option) => option.type === "effort")
|
||||||
body: { ...(item.provider?.body ?? {}) },
|
for (const value of option?.values ?? []) {
|
||||||
}))
|
const id = value === null ? "none" : value
|
||||||
|
if (typeof id !== "string") continue
|
||||||
|
const variantID = ModelV2.VariantID.make(id)
|
||||||
|
result.set(variantID, {
|
||||||
|
id: variantID,
|
||||||
|
headers: {},
|
||||||
|
body:
|
||||||
|
packageName === "@ai-sdk/openai"
|
||||||
|
? { include: ["reasoning.encrypted_content"], reasoning: { effort: id, summary: "auto" } }
|
||||||
|
: { reasoning_effort: id },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 mergeVariants(model: ModelV2Info, next: ModelV2Info["variants"]) {
|
function mergeVariants(model: ModelV2Info, next: ModelV2Info["variants"]) {
|
||||||
@@ -121,7 +142,7 @@ export const ModelsDevPlugin = define({
|
|||||||
input: [...(model.modalities?.input ?? [])],
|
input: [...(model.modalities?.input ?? [])],
|
||||||
output: [...(model.modalities?.output ?? [])],
|
output: [...(model.modalities?.output ?? [])],
|
||||||
}
|
}
|
||||||
mergeVariants(draft, variants(model))
|
mergeVariants(draft, variants(model, model.provider?.npm ?? item.npm))
|
||||||
draft.time.released = released(model.release_date)
|
draft.time.released = released(model.release_date)
|
||||||
draft.cost = cost(model.cost)
|
draft.cost = cost(model.cost)
|
||||||
draft.status = model.status ?? "active"
|
draft.status = model.status ?? "active"
|
||||||
|
|||||||
@@ -9,26 +9,25 @@
|
|||||||
"id": "local",
|
"id": "local",
|
||||||
"name": "Local",
|
"name": "Local",
|
||||||
"env": [],
|
"env": [],
|
||||||
|
"models": {}
|
||||||
|
},
|
||||||
|
"opencode": {
|
||||||
|
"id": "opencode",
|
||||||
|
"name": "OpenCode",
|
||||||
|
"env": [],
|
||||||
|
"npm": "@ai-sdk/openai-compatible",
|
||||||
"models": {
|
"models": {
|
||||||
"model": {
|
"gpt-5.5": {
|
||||||
"id": "model",
|
"id": "gpt-5.5",
|
||||||
"name": "Local Model",
|
"name": "GPT-5.5",
|
||||||
"release_date": "2026-01-01",
|
"release_date": "2026-04-23",
|
||||||
"attachment": false,
|
"attachment": true,
|
||||||
"reasoning": true,
|
"reasoning": true,
|
||||||
"temperature": true,
|
"reasoning_options": [{ "type": "effort", "values": [null, "none", "low", "medium", "high", "xhigh"] }],
|
||||||
|
"temperature": false,
|
||||||
"tool_call": true,
|
"tool_call": true,
|
||||||
"limit": { "context": 1000, "output": 100 },
|
"limit": { "context": 400000, "output": 128000 },
|
||||||
"experimental": {
|
"provider": { "npm": "@ai-sdk/openai", "api": "https://console.opencode.ai/inference/openai/v1" }
|
||||||
"modes": {
|
|
||||||
"high": {
|
|
||||||
"provider": { "body": { "reasoning_effort": "high" } }
|
|
||||||
},
|
|
||||||
"max": {
|
|
||||||
"provider": { "headers": { "x-variant": "max" }, "body": { "reasoning_effort": "max" } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ describe("ModelsDevPlugin", () => {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.effect("loads models.dev variants without replacing existing variants", () =>
|
it.effect("derives OpenAI reasoning variants from models.dev reasoning options", () =>
|
||||||
Effect.acquireUseRelease(
|
Effect.acquireUseRelease(
|
||||||
Effect.sync(() => {
|
Effect.sync(() => {
|
||||||
const previous = {
|
const previous = {
|
||||||
@@ -89,27 +89,61 @@ describe("ModelsDevPlugin", () => {
|
|||||||
}),
|
}),
|
||||||
() =>
|
() =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const service = yield* Catalog.Service
|
const catalog = yield* Catalog.Service
|
||||||
const integrations = yield* Integration.Service
|
const integrations = yield* Integration.Service
|
||||||
yield* service.transform((catalog) => {
|
yield* catalog.transform((catalog) => {
|
||||||
catalog.model.update(ProviderV2.ID.make("local"), ModelV2.ID.make("model"), (model) => {
|
catalog.model.update(ProviderV2.ID.opencode, ModelV2.ID.make("gpt-5.5"), (model) => {
|
||||||
model.variants = [
|
model.variants = [
|
||||||
{ id: ModelV2.VariantID.make("high"), headers: { custom: "true" }, body: {} },
|
{
|
||||||
{ id: ModelV2.VariantID.make("custom"), headers: {}, body: { custom: true } },
|
id: ModelV2.VariantID.make("high"),
|
||||||
|
headers: { custom: "true" },
|
||||||
|
body: { custom: true },
|
||||||
|
},
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
yield* ModelsDevPlugin.effect(
|
yield* ModelsDevPlugin.effect(
|
||||||
host({
|
host({
|
||||||
catalog: catalogHost(service),
|
catalog: catalogHost(catalog),
|
||||||
integration: integrationHost(integrations),
|
integration: integrationHost(integrations),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
expect((yield* service.model.get(ProviderV2.ID.make("local"), ModelV2.ID.make("model")))?.variants).toEqual([
|
expect((yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("gpt-5.5")))?.variants).toEqual([
|
||||||
expect.objectContaining({ id: "high", headers: { custom: "true" } }),
|
{
|
||||||
expect.objectContaining({ id: "max", headers: { "x-variant": "max" }, body: { reasoning_effort: "max" } }),
|
id: ModelV2.VariantID.make("none"),
|
||||||
expect.objectContaining({ id: "custom", body: { custom: true } }),
|
headers: {},
|
||||||
|
body: {
|
||||||
|
include: ["reasoning.encrypted_content"],
|
||||||
|
reasoning: { effort: "none", summary: "auto" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "low",
|
||||||
|
body: {
|
||||||
|
include: ["reasoning.encrypted_content"],
|
||||||
|
reasoning: { effort: "low", summary: "auto" },
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "medium",
|
||||||
|
body: {
|
||||||
|
include: ["reasoning.encrypted_content"],
|
||||||
|
reasoning: { effort: "medium", summary: "auto" },
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "high",
|
||||||
|
headers: { custom: "true" },
|
||||||
|
body: { custom: true },
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "xhigh",
|
||||||
|
body: {
|
||||||
|
include: ["reasoning.encrypted_content"],
|
||||||
|
reasoning: { effort: "xhigh", summary: "auto" },
|
||||||
|
},
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
}).pipe(Effect.provide(ModelsDev.defaultLayer)),
|
}).pipe(Effect.provide(ModelsDev.defaultLayer)),
|
||||||
(previous) =>
|
(previous) =>
|
||||||
@@ -119,4 +153,5 @@ describe("ModelsDevPlugin", () => {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user