Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 278361cb48 |
@@ -153,6 +153,7 @@ export type AgentListOutput = {
|
||||
readonly request: {
|
||||
readonly headers: { readonly [x: string]: string }
|
||||
readonly body: { readonly [x: string]: JsonValue }
|
||||
readonly providerOptions?: { readonly [x: string]: { readonly [x: string]: JsonValue } }
|
||||
}
|
||||
readonly system?: string
|
||||
readonly description?: string
|
||||
@@ -2147,12 +2148,14 @@ export type ModelListOutput = {
|
||||
readonly request: {
|
||||
readonly headers: { readonly [x: string]: string }
|
||||
readonly body: { readonly [x: string]: JsonValue }
|
||||
readonly providerOptions?: { readonly [x: string]: { readonly [x: string]: JsonValue } }
|
||||
readonly variant?: string
|
||||
}
|
||||
readonly variants: ReadonlyArray<{
|
||||
readonly id: string
|
||||
readonly headers: { readonly [x: string]: string }
|
||||
readonly body: { readonly [x: string]: JsonValue }
|
||||
readonly providerOptions?: { readonly [x: string]: { readonly [x: string]: JsonValue } }
|
||||
}>
|
||||
readonly time: { readonly released: number }
|
||||
readonly cost: ReadonlyArray<{
|
||||
@@ -2211,6 +2214,7 @@ export type ProviderListOutput = {
|
||||
readonly request: {
|
||||
readonly headers: { readonly [x: string]: string }
|
||||
readonly body: { readonly [x: string]: JsonValue }
|
||||
readonly providerOptions?: { readonly [x: string]: { readonly [x: string]: JsonValue } }
|
||||
}
|
||||
}>
|
||||
}
|
||||
@@ -2244,6 +2248,7 @@ export type ProviderGetOutput = {
|
||||
readonly request: {
|
||||
readonly headers: { readonly [x: string]: string }
|
||||
readonly body: { readonly [x: string]: JsonValue }
|
||||
readonly providerOptions?: { readonly [x: string]: { readonly [x: string]: JsonValue } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,12 @@ export const Plugin = define({
|
||||
if (item.request !== undefined) {
|
||||
Object.assign(provider.request.headers, item.request.headers)
|
||||
Object.assign(provider.request.body, item.request.body)
|
||||
if (item.request.providerOptions !== undefined) {
|
||||
provider.request.providerOptions = ProviderV2.mergeProviderOptions(
|
||||
provider.request.providerOptions,
|
||||
item.request.providerOptions,
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
for (const [id, config] of Object.entries(item.models ?? {})) {
|
||||
@@ -73,6 +79,12 @@ export const Plugin = define({
|
||||
if (config.request !== undefined) {
|
||||
Object.assign(model.request.headers, config.request.headers)
|
||||
Object.assign(model.request.body, config.request.body)
|
||||
if (config.request.providerOptions !== undefined) {
|
||||
model.request.providerOptions = ProviderV2.mergeProviderOptions(
|
||||
model.request.providerOptions,
|
||||
config.request.providerOptions,
|
||||
)
|
||||
}
|
||||
if (config.request.variant !== undefined) model.request.variant = config.request.variant
|
||||
}
|
||||
if (config.variants !== undefined) {
|
||||
@@ -88,6 +100,12 @@ export const Plugin = define({
|
||||
}
|
||||
Object.assign(existing.headers, variant.headers)
|
||||
Object.assign(existing.body, variant.body)
|
||||
if (variant.providerOptions !== undefined) {
|
||||
existing.providerOptions = ProviderV2.mergeProviderOptions(
|
||||
existing.providerOptions,
|
||||
variant.providerOptions,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.cost !== undefined) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { ModelV2 } from "../model"
|
||||
export class Request extends Schema.Class<Request>("ConfigV2.Provider.Request")({
|
||||
headers: Schema.Record(Schema.String, Schema.String).pipe(Schema.optional),
|
||||
body: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
||||
providerOptions: ProviderV2.ProviderOptions.pipe(Schema.optional),
|
||||
}) {}
|
||||
|
||||
class Cache extends Schema.Class<Cache>("ConfigV2.Model.Cost.Cache")({
|
||||
|
||||
@@ -26,8 +26,13 @@ export type Api = Model.Api
|
||||
export const Info = Model.Info
|
||||
export type Info = Model.Info
|
||||
|
||||
export type MutableInfo = Omit<Types.DeepMutable<Info>, "api"> & {
|
||||
export type MutableRequest = ProviderV2.MutableRequest & { variant?: string }
|
||||
export type MutableVariant = ProviderV2.MutableRequest & { id: VariantID }
|
||||
|
||||
export type MutableInfo = Omit<Types.DeepMutable<Info>, "api" | "request" | "variants"> & {
|
||||
api: ProviderV2.MutableApi<Api>
|
||||
request: MutableRequest
|
||||
variants: MutableVariant[]
|
||||
}
|
||||
|
||||
export function parse(input: string): { providerID: ProviderV2.ID; modelID: ID } {
|
||||
|
||||
@@ -70,25 +70,75 @@ function mergeCost(base: ModelV2Info["cost"], override: ModelsDev.Model["cost"]
|
||||
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")
|
||||
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 },
|
||||
})
|
||||
const OPENAI_INCLUDE_ENCRYPTED_REASONING = ["reasoning.encrypted_content"]
|
||||
|
||||
function reasoningVariants(provider: ModelsDev.Provider, model: ModelsDev.Model): ModelV2Info["variants"] {
|
||||
const npm = model.provider?.npm ?? provider.npm
|
||||
const options = model.reasoning_options ?? []
|
||||
const effort = options.find((option) => option.type === "effort")
|
||||
if (effort?.type === "effort") {
|
||||
return effort.values.flatMap((value) => {
|
||||
const raw: unknown = value
|
||||
const id = raw === null ? "none" : typeof raw === "string" ? raw : undefined
|
||||
if (id === undefined) return []
|
||||
const providerOptions = providerOptionsForEffort(npm, id)
|
||||
return providerOptions ? [{ id, headers: {}, body: {}, providerOptions }] : []
|
||||
})
|
||||
}
|
||||
|
||||
const budget = options.find((option) => option.type === "budget_tokens")
|
||||
if (budget?.type === "budget_tokens") return budgetVariants(npm, budget)
|
||||
|
||||
// Toggle-only reasoning is intentionally left for a follow-up because V1 has
|
||||
// provider/model-specific behavior like MiniMax M3 adaptive thinking and
|
||||
// Qwen/GLM enable_thinking request shapes in packages/opencode.
|
||||
return []
|
||||
}
|
||||
|
||||
function providerOptionsForEffort(npm: string | undefined, effort: string): ProviderV2.ProviderOptions | undefined {
|
||||
if (npm === "@openrouter/ai-sdk-provider") return { openrouter: { reasoning: { effort } } }
|
||||
if (npm === "@ai-sdk/anthropic" || npm === "@ai-sdk/google-vertex/anthropic") {
|
||||
return { anthropic: { thinking: { type: "adaptive" }, effort } }
|
||||
}
|
||||
if (npm === "@ai-sdk/google" || npm === "@ai-sdk/google-vertex") {
|
||||
return { gemini: { thinkingConfig: { includeThoughts: true, thinkingLevel: effort } } }
|
||||
}
|
||||
if (npm === "@ai-sdk/azure") return { openai: { reasoningEffort: effort }, azure: { reasoningEffort: effort } }
|
||||
if (npm === "@ai-sdk/openai") {
|
||||
return {
|
||||
openai: {
|
||||
reasoningEffort: effort,
|
||||
reasoningSummary: "auto",
|
||||
include: OPENAI_INCLUDE_ENCRYPTED_REASONING,
|
||||
},
|
||||
}
|
||||
}
|
||||
return [...result.values()]
|
||||
if (npm === "@ai-sdk/openai-compatible") return { openai: { reasoningEffort: effort } }
|
||||
}
|
||||
|
||||
function budgetVariants(
|
||||
npm: string | undefined,
|
||||
option: Extract<NonNullable<ModelsDev.Model["reasoning_options"]>[number], { type: "budget_tokens" }>,
|
||||
): ModelV2Info["variants"] {
|
||||
const max = option.max
|
||||
const high = option.max === undefined ? Math.max(option.min ?? 0, 16_000) : Math.min(Math.max(option.min ?? 0, 16_000), option.max)
|
||||
return [
|
||||
{ id: "high", budget: high },
|
||||
...(max === undefined || max === high ? [] : [{ id: "max", budget: max }]),
|
||||
].flatMap((item) => {
|
||||
const providerOptions = providerOptionsForBudget(npm, item.budget)
|
||||
return providerOptions ? [{ id: item.id, headers: {}, body: {}, providerOptions }] : []
|
||||
})
|
||||
}
|
||||
|
||||
function providerOptionsForBudget(npm: string | undefined, budget: number): ProviderV2.ProviderOptions | undefined {
|
||||
if (npm === "@openrouter/ai-sdk-provider") return { openrouter: { reasoning: { max_tokens: budget } } }
|
||||
if (npm === "@ai-sdk/anthropic" || npm === "@ai-sdk/google-vertex/anthropic") {
|
||||
return { anthropic: { thinking: { type: "enabled", budgetTokens: budget } } }
|
||||
}
|
||||
if (npm === "@ai-sdk/google" || npm === "@ai-sdk/google-vertex") {
|
||||
return { gemini: { thinkingConfig: { includeThoughts: true, thinkingBudget: budget } } }
|
||||
}
|
||||
}
|
||||
|
||||
function modeName(model: ModelsDev.Model, mode: string) {
|
||||
@@ -193,7 +243,7 @@ export const ModelsDevPlugin = define({
|
||||
|
||||
for (const model of Object.values(item.models)) {
|
||||
const baseCost = cost(model.cost)
|
||||
const variants = reasoningVariants(model, model.provider?.npm ?? item.npm)
|
||||
const variants = reasoningVariants(item, model)
|
||||
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) =>
|
||||
|
||||
@@ -19,7 +19,26 @@ export type MutableApi<T extends Api = Api> = T extends Api
|
||||
export const Request = Provider.Request
|
||||
export type Request = Provider.Request
|
||||
|
||||
export const ProviderOptions = Provider.ProviderOptions
|
||||
export type ProviderOptions = Provider.ProviderOptions
|
||||
|
||||
export const mergeProviderOptions = (...items: ReadonlyArray<ProviderOptions | undefined>): ProviderOptions | undefined => {
|
||||
const result: Record<string, ProviderOptions[string]> = {}
|
||||
for (const item of items) {
|
||||
if (!item) continue
|
||||
for (const [provider, options] of Object.entries(item)) {
|
||||
result[provider] = { ...result[provider], ...options }
|
||||
}
|
||||
}
|
||||
return Object.keys(result).length === 0 ? undefined : result
|
||||
}
|
||||
|
||||
export const Info = Provider.Info
|
||||
export type Info = Provider.Info
|
||||
|
||||
export type MutableInfo = Omit<Types.DeepMutable<Info>, "api"> & { api: MutableApi }
|
||||
export type MutableRequest = Omit<Types.DeepMutable<Request>, "providerOptions"> & { providerOptions?: ProviderOptions }
|
||||
|
||||
export type MutableInfo = Omit<Types.DeepMutable<Info>, "api" | "request"> & {
|
||||
api: MutableApi
|
||||
request: MutableRequest
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ const withDefaults = (model: ModelV2.Info, route: AnyRoute) => {
|
||||
provider: model.providerID,
|
||||
endpoint: model.api.url === undefined ? undefined : { baseURL: model.api.url },
|
||||
headers: model.request.headers,
|
||||
providerOptions: model.request.providerOptions,
|
||||
http: { body: httpBody },
|
||||
limits: { context: model.limit.context, output: model.limit.output },
|
||||
})
|
||||
@@ -120,6 +121,12 @@ export const withVariant = (
|
||||
? produce(model, (draft) => {
|
||||
Object.assign(draft.request.headers, variant.headers)
|
||||
Object.assign(draft.request.body, variant.body)
|
||||
if (variant.providerOptions !== undefined) {
|
||||
draft.request.providerOptions = ProviderV2.mergeProviderOptions(
|
||||
draft.request.providerOptions,
|
||||
variant.providerOptions,
|
||||
)
|
||||
}
|
||||
})
|
||||
: model,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"openai": {
|
||||
"id": "openai",
|
||||
"name": "OpenAI",
|
||||
"env": ["OPENAI_API_KEY"],
|
||||
"npm": "@ai-sdk/openai",
|
||||
"api": "https://api.openai.com/v1",
|
||||
"models": {
|
||||
"gpt-reasoning": {
|
||||
"id": "gpt-reasoning",
|
||||
"name": "GPT Reasoning",
|
||||
"release_date": "2026-01-01",
|
||||
"attachment": false,
|
||||
"reasoning": true,
|
||||
"reasoning_options": [
|
||||
{ "type": "effort", "values": ["low", "high"] },
|
||||
{ "type": "budget_tokens", "min": 1024, "max": 64000 },
|
||||
{ "type": "toggle" }
|
||||
],
|
||||
"temperature": true,
|
||||
"tool_call": true,
|
||||
"limit": { "context": 128000, "output": 8192 },
|
||||
"experimental": {
|
||||
"modes": {
|
||||
"high": {
|
||||
"provider": {
|
||||
"headers": { "x-mode": "high" },
|
||||
"body": { "service_tier": "priority" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"anthropic": {
|
||||
"id": "anthropic",
|
||||
"name": "Anthropic",
|
||||
"env": ["ANTHROPIC_API_KEY"],
|
||||
"npm": "@ai-sdk/anthropic",
|
||||
"api": "https://api.anthropic.com/v1",
|
||||
"models": {
|
||||
"claude-budget": {
|
||||
"id": "claude-budget",
|
||||
"name": "Claude Budget",
|
||||
"release_date": "2026-01-01",
|
||||
"attachment": false,
|
||||
"reasoning": true,
|
||||
"reasoning_options": [{ "type": "budget_tokens", "min": 1024, "max": 64000 }],
|
||||
"temperature": true,
|
||||
"tool_call": true,
|
||||
"limit": { "context": 128000, "output": 8192 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,14 +173,14 @@ describe("ModelsDevPlugin", () => {
|
||||
),
|
||||
)
|
||||
|
||||
it.effect("derives OpenAI reasoning variants from models.dev reasoning options", () =>
|
||||
it.effect("converts reasoning options into provider option variants", () =>
|
||||
Effect.acquireUseRelease(
|
||||
Effect.sync(() => {
|
||||
const previous = {
|
||||
path: Flag.OPENCODE_MODELS_PATH,
|
||||
disabled: Flag.OPENCODE_DISABLE_MODELS_FETCH,
|
||||
}
|
||||
Flag.OPENCODE_MODELS_PATH = path.join(import.meta.dir, "fixtures", "models-dev.json")
|
||||
Flag.OPENCODE_MODELS_PATH = path.join(import.meta.dir, "fixtures", "models-dev-reasoning.json")
|
||||
Flag.OPENCODE_DISABLE_MODELS_FETCH = true
|
||||
return previous
|
||||
}),
|
||||
@@ -188,17 +188,6 @@ describe("ModelsDevPlugin", () => {
|
||||
Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
const integrations = yield* Integration.Service
|
||||
yield* catalog.transform((catalog) => {
|
||||
catalog.model.update(ProviderV2.ID.opencode, ModelV2.ID.make("gpt-5.5"), (model) => {
|
||||
model.variants = [
|
||||
{
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
headers: { custom: "true" },
|
||||
body: { custom: true },
|
||||
},
|
||||
]
|
||||
})
|
||||
})
|
||||
yield* ModelsDevPlugin.effect(
|
||||
host({
|
||||
catalog: catalogHost(catalog),
|
||||
@@ -206,42 +195,67 @@ describe("ModelsDevPlugin", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
expect((yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("gpt-5.5")))?.variants).toEqual([
|
||||
{
|
||||
id: ModelV2.VariantID.make("none"),
|
||||
headers: {},
|
||||
body: {
|
||||
const model = yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-reasoning"))
|
||||
expect(model?.variants.map((variant) => variant.id)).toEqual([
|
||||
ModelV2.VariantID.make("low"),
|
||||
ModelV2.VariantID.make("high"),
|
||||
])
|
||||
expect(model?.variants).toContainEqual({
|
||||
id: ModelV2.VariantID.make("low"),
|
||||
headers: {},
|
||||
body: {},
|
||||
providerOptions: {
|
||||
openai: {
|
||||
reasoningEffort: "low",
|
||||
reasoningSummary: "auto",
|
||||
include: ["reasoning.encrypted_content"],
|
||||
reasoning: { effort: "none", summary: "auto" },
|
||||
},
|
||||
},
|
||||
expect.objectContaining({
|
||||
id: "low",
|
||||
body: {
|
||||
})
|
||||
expect(model?.variants).toContainEqual({
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
headers: {},
|
||||
body: {},
|
||||
providerOptions: {
|
||||
openai: {
|
||||
reasoningEffort: "high",
|
||||
reasoningSummary: "auto",
|
||||
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" },
|
||||
},
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
const mode = yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-reasoning-high"))
|
||||
expect(mode).toMatchObject({
|
||||
id: "gpt-reasoning-high",
|
||||
name: "GPT Reasoning High",
|
||||
request: {
|
||||
headers: { "x-mode": "high" },
|
||||
body: { service_tier: "priority" },
|
||||
},
|
||||
})
|
||||
expect(mode?.variants.map((variant) => variant.id)).toEqual([
|
||||
ModelV2.VariantID.make("low"),
|
||||
ModelV2.VariantID.make("high"),
|
||||
])
|
||||
|
||||
const budgetModel = yield* catalog.model.get(ProviderV2.ID.anthropic, ModelV2.ID.make("claude-budget"))
|
||||
expect(budgetModel?.variants).toContainEqual({
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
headers: {},
|
||||
body: {},
|
||||
providerOptions: {
|
||||
anthropic: { thinking: { type: "enabled", budgetTokens: 16000 } },
|
||||
},
|
||||
})
|
||||
expect(budgetModel?.variants).toContainEqual({
|
||||
id: ModelV2.VariantID.make("max"),
|
||||
headers: {},
|
||||
body: {},
|
||||
providerOptions: {
|
||||
anthropic: { thinking: { type: "enabled", budgetTokens: 64000 } },
|
||||
},
|
||||
})
|
||||
}).pipe(Effect.provide(ModelsDev.defaultLayer)),
|
||||
(previous) =>
|
||||
Effect.sync(() => {
|
||||
@@ -250,5 +264,4 @@ describe("ModelsDevPlugin", () => {
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
})
|
||||
|
||||
@@ -106,6 +106,7 @@ describe("SessionRunnerModel", () => {
|
||||
{
|
||||
id: ModelV2.VariantID.make("high"),
|
||||
headers: { "x-variant": "high" },
|
||||
providerOptions: { openai: { reasoningEffort: "high" } },
|
||||
body: {
|
||||
store: false,
|
||||
service_tier: "priority",
|
||||
@@ -139,6 +140,9 @@ describe("SessionRunnerModel", () => {
|
||||
temperature: 0.2,
|
||||
reasoning: { effort: "high" },
|
||||
})
|
||||
expect(resolved.route.defaults.providerOptions).toEqual({
|
||||
openai: { store: false, reasoningEffort: "high" },
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
@@ -43,10 +43,16 @@ export const Api = Schema.Union([AISDK, Native])
|
||||
.annotate({ identifier: "Provider.Api" })
|
||||
export type Api = typeof Api.Type
|
||||
|
||||
export const ProviderOptions = Schema.Record(Schema.String, Schema.Record(Schema.String, Schema.Unknown)).annotate({
|
||||
identifier: "Provider.Options",
|
||||
})
|
||||
export type ProviderOptions = typeof ProviderOptions.Type
|
||||
|
||||
export interface Request extends Schema.Schema.Type<typeof Request> {}
|
||||
export const Request = Schema.Struct({
|
||||
headers: Schema.Record(Schema.String, Schema.String),
|
||||
body: Schema.Record(Schema.String, Schema.Json),
|
||||
providerOptions: ProviderOptions.pipe(optional),
|
||||
}).annotate({ identifier: "Provider.Request" })
|
||||
|
||||
export interface Info extends Schema.Schema.Type<typeof Info> {}
|
||||
|
||||
@@ -4077,6 +4077,12 @@ export type LocationInfo = {
|
||||
}
|
||||
}
|
||||
|
||||
export type ProviderOptions = {
|
||||
[key: string]: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type ProviderRequest = {
|
||||
headers: {
|
||||
[key: string]: string
|
||||
@@ -4084,6 +4090,7 @@ export type ProviderRequest = {
|
||||
body: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
providerOptions?: ProviderOptions
|
||||
}
|
||||
|
||||
export type AgentColor = string | "primary" | "secondary" | "accent" | "success" | "warning" | "error" | "info"
|
||||
@@ -5106,6 +5113,7 @@ export type ModelV2Info = {
|
||||
body: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
providerOptions?: ProviderOptions
|
||||
variant?: string
|
||||
}
|
||||
variants: Array<{
|
||||
@@ -5116,6 +5124,7 @@ export type ModelV2Info = {
|
||||
body: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
providerOptions?: ProviderOptions
|
||||
}>
|
||||
time: {
|
||||
released: number
|
||||
|
||||
Reference in New Issue
Block a user