refactor(core): nest model api id (#30603)

This commit is contained in:
Dax 2026-06-03 14:11:38 -04:00 committed by GitHub
commit 11dbd15812
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
35 changed files with 129 additions and 79 deletions

View file

@ -164,7 +164,7 @@ export const layer = Layer.effect(
{},
)
.pipe(initError(model.providerID))
const language = yield* Effect.sync(() => result.language ?? sdk.languageModel(model.apiID)).pipe(
const language = yield* Effect.sync(() => result.language ?? sdk.languageModel(model.api.id)).pipe(
initError(model.providerID),
)
languages.set(key, language)

View file

@ -99,7 +99,7 @@ export const layer = Layer.effect(
const provider = state.get().providers.get(model.providerID)!.provider
const api =
model.api.type === "native" && !model.api.url && Object.keys(model.api.settings).length === 0
? provider.api
? { ...provider.api, id: model.api.id }
: model.api.type === "aisdk" && provider.api.type === "aisdk" && !model.api.url
? { ...model.api, url: provider.api.url, settings: { ...provider.api.settings, ...model.api.settings } }
: model.api.type === "aisdk" && provider.api.type === "aisdk"

View file

@ -32,10 +32,9 @@ export const Plugin = PluginV2.define({
for (const [id, config] of Object.entries(item.models ?? {})) {
catalog.model.update(providerID, ModelV2.ID.make(id), (model) => {
if (config.api_id !== undefined) model.apiID = config.api_id
if (config.family !== undefined) model.family = config.family
if (config.name !== undefined) model.name = config.name
if (config.api !== undefined) model.api = { ...config.api }
if (config.api !== undefined) model.api = { ...model.api, ...config.api }
if (config.capabilities !== undefined) {
model.capabilities = {
tools: config.capabilities.tools,

View file

@ -30,11 +30,24 @@ class Limit extends Schema.Class<Limit>("ConfigV2.Model.Limit")({
output: Schema.Int.pipe(Schema.optional),
}) {}
const ModelApi = Schema.Union([
Schema.Struct({
id: ModelV2.ID.pipe(Schema.optional),
...ProviderV2.AISDK.fields,
}),
Schema.Struct({
id: ModelV2.ID.pipe(Schema.optional),
...ProviderV2.Native.fields,
}),
Schema.Struct({
id: ModelV2.ID,
}),
])
class Model extends Schema.Class<Model>("ConfigV2.Model")({
api_id: ModelV2.ID.pipe(Schema.optional),
family: ModelV2.Family.pipe(Schema.optional),
name: Schema.String.pipe(Schema.optional),
api: ProviderV2.Api.pipe(Schema.optional),
api: ModelApi.pipe(Schema.optional),
capabilities: ModelV2.Capabilities.pipe(Schema.optional),
request: Schema.Struct({
...Request.fields,

View file

@ -40,13 +40,24 @@ export const Ref = Schema.Struct({
})
export type Ref = typeof Ref.Type
export const Api = Schema.Union([
Schema.Struct({
id: ID,
...ProviderV2.AISDK.fields,
}),
Schema.Struct({
id: ID,
...ProviderV2.Native.fields,
}),
]).pipe(Schema.toTaggedUnion("type"))
export type Api = typeof Api.Type
export class Info extends Schema.Class<Info>("ModelV2.Info")({
id: ID,
apiID: ID,
providerID: ProviderV2.ID,
family: Family.pipe(Schema.optional),
name: Schema.String,
api: ProviderV2.Api,
api: Api,
capabilities: Capabilities,
request: Schema.Struct({
...ProviderV2.Request.fields,
@ -71,10 +82,10 @@ export class Info extends Schema.Class<Info>("ModelV2.Info")({
static empty(providerID: ProviderV2.ID, modelID: ID): Info {
return new Info({
id: modelID,
apiID: modelID,
providerID,
name: modelID,
api: {
id: modelID,
type: "native",
settings: {},
},

View file

@ -82,11 +82,13 @@ export const ModelsDevPlugin = PluginV2.define({
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: {},

View file

@ -92,7 +92,7 @@ export const AmazonBedrockPlugin = PluginV2.define({
"aisdk.language": Effect.fn(function* (evt) {
if (evt.model.providerID !== ProviderV2.ID.amazonBedrock) return
const region = typeof evt.options.region === "string" ? evt.options.region : process.env.AWS_REGION
evt.language = evt.sdk.languageModel(resolveModelID(evt.model.apiID, region))
evt.language = evt.sdk.languageModel(resolveModelID(evt.model.api.id, region))
}),
}
}),

View file

@ -45,7 +45,7 @@ export const AzurePlugin = PluginV2.define({
}),
"aisdk.language": Effect.fn(function* (evt) {
if (evt.model.providerID !== ProviderV2.ID.azure) return
evt.language = selectLanguage(evt.sdk, evt.model.apiID, Boolean(evt.options.useCompletionUrls))
evt.language = selectLanguage(evt.sdk, evt.model.api.id, Boolean(evt.options.useCompletionUrls))
}),
}
}),
@ -69,7 +69,7 @@ export const AzureCognitiveServicesPlugin = PluginV2.define({
}),
"aisdk.language": Effect.fn(function* (evt) {
if (evt.model.providerID !== ProviderV2.ID.make("azure-cognitive-services")) return
evt.language = selectLanguage(evt.sdk, evt.model.apiID, Boolean(evt.options.useCompletionUrls))
evt.language = selectLanguage(evt.sdk, evt.model.api.id, Boolean(evt.options.useCompletionUrls))
}),
}
}),

View file

@ -30,7 +30,7 @@ export const CloudflareWorkersAIPlugin = PluginV2.define({
}),
"aisdk.language": Effect.fn(function* (evt) {
if (evt.model.providerID !== providerID) return
evt.language = evt.sdk.languageModel(evt.model.apiID)
evt.language = evt.sdk.languageModel(evt.model.api.id)
}),
}
}),

View file

@ -23,12 +23,12 @@ export const GithubCopilotPlugin = PluginV2.define({
"aisdk.language": Effect.fn(function* (evt) {
if (evt.model.providerID !== ProviderV2.ID.githubCopilot) return
if (evt.sdk.responses === undefined && evt.sdk.chat === undefined) {
evt.language = evt.sdk.languageModel(evt.model.apiID)
evt.language = evt.sdk.languageModel(evt.model.api.id)
return
}
evt.language = shouldUseResponses(evt.model.apiID)
? evt.sdk.responses(evt.model.apiID)
: evt.sdk.chat(evt.model.apiID)
evt.language = shouldUseResponses(evt.model.api.id)
? evt.sdk.responses(evt.model.api.id)
: evt.sdk.chat(evt.model.api.id)
}),
"catalog.transform": Effect.fn(function* (evt) {
const item = evt.provider.get(ProviderV2.ID.githubCopilot)

View file

@ -34,7 +34,7 @@ export const GitLabPlugin = PluginV2.define({
if (evt.model.providerID !== ProviderV2.ID.gitlab) return
const featureFlags =
typeof evt.options.featureFlags === "object" && evt.options.featureFlags ? evt.options.featureFlags : {}
if (evt.model.apiID.startsWith("duo-workflow-")) {
if (evt.model.api.id.startsWith("duo-workflow-")) {
const gitlab = yield* Effect.promise(() => import("gitlab-ai-provider")).pipe(Effect.orDie)
const workflowRef =
typeof evt.model.request.body.workflowRef === "string" ? evt.model.request.body.workflowRef : undefined
@ -43,7 +43,7 @@ export const GitLabPlugin = PluginV2.define({
? evt.model.request.body.workflowDefinition
: undefined
const language = evt.sdk.workflowChat(
gitlab.isWorkflowModel(evt.model.apiID) ? evt.model.apiID : "duo-workflow",
gitlab.isWorkflowModel(evt.model.api.id) ? evt.model.api.id : "duo-workflow",
{
featureFlags,
workflowDefinition,
@ -53,7 +53,7 @@ export const GitLabPlugin = PluginV2.define({
evt.language = language
return
}
evt.language = evt.sdk.agenticChat(evt.model.apiID, {
evt.language = evt.sdk.agenticChat(evt.model.api.id, {
aiGatewayHeaders: evt.options.aiGatewayHeaders,
featureFlags,
})

View file

@ -99,7 +99,7 @@ export const GoogleVertexPlugin = PluginV2.define({
}),
"aisdk.language": Effect.fn(function* (evt) {
if (evt.model.providerID !== ProviderV2.ID.googleVertex) return
evt.language = evt.sdk.languageModel(String(evt.model.apiID).trim())
evt.language = evt.sdk.languageModel(String(evt.model.api.id).trim())
}),
}
}),
@ -155,7 +155,7 @@ export const GoogleVertexAnthropicPlugin = PluginV2.define({
}),
"aisdk.language": Effect.fn(function* (evt) {
if (evt.model.providerID !== ProviderV2.ID.make("google-vertex-anthropic")) return
evt.language = evt.sdk.languageModel(String(evt.model.apiID).trim())
evt.language = evt.sdk.languageModel(String(evt.model.api.id).trim())
}),
}
}),

View file

@ -14,7 +14,7 @@ export const OpenAIPlugin = PluginV2.define({
}),
"aisdk.language": Effect.fn(function* (evt) {
if (evt.model.providerID !== ProviderV2.ID.openai) return
evt.language = evt.sdk.responses(evt.model.apiID)
evt.language = evt.sdk.responses(evt.model.api.id)
}),
"catalog.transform": Effect.fn(function* (evt) {
for (const item of evt.provider.list()) {

View file

@ -37,7 +37,7 @@ export const SapAICorePlugin = PluginV2.define({
}),
"aisdk.language": Effect.fn(function* (evt) {
if (evt.model.providerID !== ProviderV2.ID.make("sap-ai-core")) return
evt.language = evt.sdk(evt.model.apiID)
evt.language = evt.sdk(evt.model.api.id)
}),
}
}),

View file

@ -13,7 +13,7 @@ export const XAIPlugin = PluginV2.define({
}),
"aisdk.language": Effect.fn(function* (evt) {
if (evt.model.providerID !== ProviderV2.ID.make("xai")) return
evt.language = evt.sdk.responses(evt.model.apiID)
evt.language = evt.sdk.responses(evt.model.api.id)
}),
}
}),

View file

@ -25,14 +25,14 @@ export type ID = typeof ID.Type
export const ModelID = Schema.String.pipe(Schema.brand("ModelID"))
export type ModelID = typeof ModelID.Type
const AISDK = Schema.Struct({
export const AISDK = Schema.Struct({
type: Schema.Literal("aisdk"),
package: Schema.String,
url: Schema.String.pipe(Schema.optional),
settings: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
})
const Native = Schema.Struct({
export const Native = Schema.Struct({
type: Schema.Literal("native"),
url: Schema.String.pipe(Schema.optional),
settings: Schema.Record(Schema.String, Schema.Unknown),

View file

@ -205,12 +205,19 @@ function migrateModel(info: typeof ConfigProviderV1.Model.Type, packageName?: st
: undefined
const lowerer = ConfigProviderOptionsV1.get(info.provider?.npm ?? packageName)
return {
api_id: info.id,
family: info.family,
name: info.name,
api: info.provider?.npm
? { type: "aisdk" as const, package: info.provider.npm, url: info.provider.api, settings: {} }
: undefined,
? {
...(info.id === undefined ? {} : { id: info.id }),
type: "aisdk" as const,
package: info.provider.npm,
url: info.provider.api,
settings: {},
}
: info.id === undefined
? undefined
: { id: info.id },
capabilities,
request: (info.headers || info.options) && {
headers: info.headers,