Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 43 additions & 11 deletions packages/core/src/aisdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ function wrapSSE(res: Response, ms: number, ctl: AbortController) {
}

function prepareOptions(model: ModelV2.Info, pkg: string) {
const projected = mapBodyToProviderOptions(model)
const projected = mapBodyToProviderOptions(model, pkg)
const options: Record<string, any> = {
name: model.providerID,
...(model.settings ?? {}),
Expand Down Expand Up @@ -265,7 +265,7 @@ export const locationLayer = Layer.effect(
cause: new Error(`Unsupported package ${model.package}`),
})

const packageName = ProviderV2.packageName(model.package) ?? ""
const packageName = ProviderV2.packageName(model.package)
const options = prepareOptions(model, packageName)
const sdkKey = cacheKey({
providerID: model.providerID,
Expand Down Expand Up @@ -301,11 +301,17 @@ export const locationLayer = Layer.effect(
export const defaultLayer = locationLayer

function modelFromLanguage(info: ModelV2.Info, language: LanguageModelV3) {
const packageName = ProviderV2.packageName(info.package)
const projected = mapBodyToProviderOptions(info)
const packageName = ProviderV2.packageName(info.package!)
const projected = mapBodyToProviderOptions(info, packageName)
const optionKey = providerOptionKey(packageName, info.providerID)
const providerOptions = (() => {
if (projected.settings === undefined) return
if (packageName === "@ai-sdk/gateway") return gatewayProviderOptions(info.modelID ?? info.id, projected.settings)
if (packageName === "@ai-sdk/azure") return { openai: projected.settings, azure: projected.settings }
return { [optionKey]: projected.settings }
})()
const route: AnyRoute = {
id: `ai-sdk:${ProviderV2.packageName(info.package) ?? "unknown"}`,
id: `ai-sdk:${packageName}`,
provider: ProviderID.make(info.providerID),
providerMetadataKey: optionKey,
protocol: "ai-sdk",
Expand All @@ -326,7 +332,7 @@ function modelFromLanguage(info: ModelV2.Info, language: LanguageModelV3) {
headers: info.headers,
},
limits: { context: info.limit.context, output: info.limit.output },
providerOptions: projected.settings === undefined ? undefined : { [optionKey]: projected.settings },
providerOptions,
},
body: {
schema: Schema.Unknown,
Expand All @@ -340,13 +346,35 @@ function modelFromLanguage(info: ModelV2.Info, language: LanguageModelV3) {
return Model.make({ id: info.modelID ?? info.id, provider: info.providerID, route })
}

function gatewayProviderOptions(modelID: ModelV2.ID, settings: Readonly<Record<string, unknown>>) {
const gateway =
typeof settings.gateway === "object" && settings.gateway !== null && !Array.isArray(settings.gateway)
? Object.fromEntries(Object.entries(settings.gateway))
: undefined
const model = Object.fromEntries(Object.entries(settings).filter(([key]) => key !== "gateway"))
if (Object.keys(model).length === 0) return gateway === undefined ? undefined : { gateway }

const separator = modelID.indexOf("/")
const prefix = separator > 0 ? modelID.slice(0, separator) : undefined
if (prefix)
return { ...(gateway === undefined ? {} : { gateway }), [prefix === "amazon" ? "bedrock" : prefix]: model }
if (typeof gateway === "object" && gateway !== null && !Array.isArray(gateway))
return { gateway: { ...gateway, ...model } }
return { gateway: model }
}

function providerOptionKey(packageName: string | undefined, providerID: ProviderV2.ID) {
if (packageName === "@ai-sdk/google") return "google"
if (packageName === "@ai-sdk/google-vertex") return "vertex"
if (packageName === "@ai-sdk/google-vertex/anthropic") return "anthropic"
if (packageName === "@ai-sdk/amazon-bedrock" || packageName === "@ai-sdk/amazon-bedrock/mantle") return "bedrock"
if (packageName === "@ai-sdk/amazon-bedrock") return "bedrock"
if (packageName === "@ai-sdk/amazon-bedrock/mantle") return "openai"
if (packageName === "@ai-sdk/azure") return "azure"
if (packageName === "@ai-sdk/github-copilot") return "copilot"
if (packageName === "@jerome-benoit/sap-ai-provider-v2") return "sap-ai"
if (packageName === "@ai-sdk/openai-compatible") return providerID.split(".")[0]
if (packageName === "@openrouter/ai-sdk-provider") return "openrouter"
if (packageName === "ai-gateway-provider") return "openaiCompatible"
if (packageName?.startsWith("@ai-sdk/")) return packageName.slice("@ai-sdk/".length)
return providerID
}
Expand All @@ -361,14 +389,18 @@ function requestSettings(settings: Readonly<Record<string, unknown>> | undefined
return Object.keys(result).length === 0 ? undefined : result
}

function mapBodyToProviderOptions(model: ModelV2.Info) {
function mapBodyToProviderOptions(model: ModelV2.Info, packageName: string) {
const settings = requestSettings(model.settings)
if (!Schema.is(Schema.Struct({ mode: Schema.Literal("pro") }))(model.body?.reasoning))
return { settings, body: model.body }
const pro = Schema.is(Schema.Struct({ mode: Schema.Literal("pro") }))(model.body?.reasoning)
const forceReasoning =
["@ai-sdk/openai", "@ai-sdk/azure", "@ai-sdk/amazon-bedrock/mantle"].includes(packageName) &&
(pro || settings?.reasoningEffort !== undefined || settings?.reasoningSummary !== undefined)
const normalized = forceReasoning ? ProviderV2.mergeOverlay(settings, { forceReasoning: true }) : settings
if (!pro) return { settings: normalized, body: model.body }
const body = { ...model.body }
delete body.reasoning
return {
settings: ProviderV2.mergeOverlay(settings, { reasoningMode: "pro" }),
settings: ProviderV2.mergeOverlay(normalized, { reasoningMode: "pro" }),
body: Object.keys(body).length === 0 ? undefined : body,
}
}
Expand Down
Loading
Loading