2025-11-13 22:39:09 +00:00
import { describe , expect , test } from "bun:test"
2026-04-27 18:33:33 +00:00
import { ProviderTransform } from "@/provider/transform"
2026-03-12 13:27:52 +00:00
import { ModelID , ProviderID } from "../../src/provider/schema"
2025-11-13 22:39:09 +00:00
2025-12-17 16:24:53 +00:00
describe ( "ProviderTransform.options - setCacheKey" , ( ) = > {
const sessionID = "test-session-123"
const mockModel = {
id : "anthropic/claude-3-5-sonnet" ,
providerID : "anthropic" ,
api : {
id : "claude-3-5-sonnet-20241022" ,
url : "https://api.anthropic.com" ,
npm : "@ai-sdk/anthropic" ,
} ,
name : "Claude 3.5 Sonnet" ,
capabilities : {
temperature : true ,
reasoning : false ,
attachment : true ,
toolcall : true ,
input : { text : true , audio : false , image : true , video : false , pdf : true } ,
output : { text : true , audio : false , image : false , video : false , pdf : false } ,
interleaved : false ,
} ,
cost : {
input : 0.003 ,
output : 0.015 ,
cache : { read : 0.0003 , write : 0.00375 } ,
} ,
l imit : {
context : 200000 ,
output : 8192 ,
} ,
status : "active" ,
options : { } ,
headers : { } ,
} as any
test ( "should set promptCacheKey when providerOptions.setCacheKey is true" , ( ) = > {
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . options ( {
model : mockModel ,
sessionID ,
providerOptions : { setCacheKey : true } ,
} )
2025-12-17 16:24:53 +00:00
expect ( result . promptCacheKey ) . toBe ( sessionID )
} )
test ( "should not set promptCacheKey when providerOptions.setCacheKey is false" , ( ) = > {
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . options ( {
model : mockModel ,
sessionID ,
providerOptions : { setCacheKey : false } ,
} )
2025-12-17 16:24:53 +00:00
expect ( result . promptCacheKey ) . toBeUndefined ( )
} )
test ( "should not set promptCacheKey when providerOptions is undefined" , ( ) = > {
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . options ( {
model : mockModel ,
sessionID ,
providerOptions : undefined ,
} )
2025-12-17 16:24:53 +00:00
expect ( result . promptCacheKey ) . toBeUndefined ( )
} )
test ( "should not set promptCacheKey when providerOptions does not have setCacheKey" , ( ) = > {
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . options ( { model : mockModel , sessionID , providerOptions : { } } )
2025-12-17 16:24:53 +00:00
expect ( result . promptCacheKey ) . toBeUndefined ( )
} )
test ( "should set promptCacheKey for openai provider regardless of setCacheKey" , ( ) = > {
const openaiModel = {
. . . mockModel ,
providerID : "openai" ,
api : {
id : "gpt-4" ,
url : "https://api.openai.com" ,
npm : "@ai-sdk/openai" ,
} ,
}
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . options ( { model : openaiModel , sessionID , providerOptions : { } } )
2025-12-17 16:24:53 +00:00
expect ( result . promptCacheKey ) . toBe ( sessionID )
} )
2026-01-15 07:31:50 +00:00
test ( "should set store=false for openai provider" , ( ) = > {
const openaiModel = {
. . . mockModel ,
providerID : "openai" ,
api : {
id : "gpt-4" ,
url : "https://api.openai.com" ,
npm : "@ai-sdk/openai" ,
} ,
}
const result = ProviderTransform . options ( {
model : openaiModel ,
sessionID ,
providerOptions : { } ,
} )
expect ( result . store ) . toBe ( false )
} )
2026-04-16 17:19:01 +00:00
2026-04-29 21:49:28 +00:00
test ( "should set store=false for azure provider by default" , ( ) = > {
2026-04-16 17:19:01 +00:00
const azureModel = {
. . . mockModel ,
providerID : "azure" ,
api : {
id : "gpt-4" ,
url : "https://azure.com" ,
npm : "@ai-sdk/azure" ,
} ,
}
const result = ProviderTransform . options ( {
model : azureModel ,
sessionID ,
providerOptions : { } ,
} )
2026-04-29 21:49:28 +00:00
expect ( result . store ) . toBe ( false )
2026-04-16 17:19:01 +00:00
} )
2025-12-17 16:24:53 +00:00
} )
2026-04-11 20:51:49 +00:00
describe ( "ProviderTransform.options - zai/zhipuai thinking" , ( ) = > {
const sessionID = "test-session-123"
const createModel = ( providerID : string ) = >
( {
id : ` ${ providerID } /glm-4.6 ` ,
providerID ,
api : {
id : "glm-4.6" ,
url : "https://open.bigmodel.cn/api/paas/v4" ,
npm : "@ai-sdk/openai-compatible" ,
} ,
name : "GLM 4.6" ,
capabilities : {
temperature : true ,
reasoning : true ,
attachment : true ,
toolcall : true ,
input : { text : true , audio : false , image : true , video : false , pdf : true } ,
output : { text : true , audio : false , image : false , video : false , pdf : false } ,
interleaved : false ,
} ,
cost : {
input : 0.001 ,
output : 0.002 ,
cache : { read : 0.0001 , write : 0.0002 } ,
} ,
limit : {
context : 128000 ,
output : 8192 ,
} ,
status : "active" ,
options : { } ,
headers : { } ,
} ) as any
for ( const providerID of [ "zai-coding-plan" , "zai" , "zhipuai-coding-plan" , "zhipuai" ] ) {
test ( ` ${ providerID } should set thinking cfg ` , ( ) = > {
const result = ProviderTransform . options ( {
model : createModel ( providerID ) ,
sessionID ,
providerOptions : { } ,
} )
expect ( result . thinking ) . toEqual ( {
type : "enabled" ,
clear_thinking : false ,
} )
} )
}
} )
2026-03-21 16:57:52 +00:00
describe ( "ProviderTransform.options - google thinkingConfig gating" , ( ) = > {
const sessionID = "test-session-123"
const createGoogleModel = ( reasoning : boolean , npm : "@ai-sdk/google" | "@ai-sdk/google-vertex" ) = >
( {
id : ` ${ npm === "@ai-sdk/google" ? "google" : "google-vertex" } /gemini-2.0-flash ` ,
providerID : npm === "@ai-sdk/google" ? "google" : "google-vertex" ,
api : {
id : "gemini-2.0-flash" ,
url : npm === "@ai-sdk/google" ? "https://generativelanguage.googleapis.com" : "https://vertexai.googleapis.com" ,
npm ,
} ,
name : "Gemini 2.0 Flash" ,
capabilities : {
temperature : true ,
reasoning ,
attachment : true ,
toolcall : true ,
input : { text : true , audio : false , image : true , video : false , pdf : true } ,
output : { text : true , audio : false , image : false , video : false , pdf : false } ,
interleaved : false ,
} ,
cost : {
input : 0.001 ,
output : 0.002 ,
cache : { read : 0.0001 , write : 0.0002 } ,
} ,
limit : {
context : 1_000_000 ,
output : 8192 ,
} ,
status : "active" ,
options : { } ,
headers : { } ,
} ) as any
test ( "does not set thinkingConfig for google models without reasoning capability" , ( ) = > {
const result = ProviderTransform . options ( {
model : createGoogleModel ( false , "@ai-sdk/google" ) ,
sessionID ,
providerOptions : { } ,
} )
expect ( result . thinkingConfig ) . toBeUndefined ( )
} )
test ( "sets thinkingConfig for google models with reasoning capability" , ( ) = > {
const result = ProviderTransform . options ( {
model : createGoogleModel ( true , "@ai-sdk/google" ) ,
sessionID ,
providerOptions : { } ,
} )
expect ( result . thinkingConfig ) . toEqual ( {
includeThoughts : true ,
} )
} )
test ( "does not set thinkingConfig for vertex models without reasoning capability" , ( ) = > {
const result = ProviderTransform . options ( {
model : createGoogleModel ( false , "@ai-sdk/google-vertex" ) ,
sessionID ,
providerOptions : { } ,
} )
expect ( result . thinkingConfig ) . toBeUndefined ( )
} )
} )
2026-01-30 20:57:01 +00:00
describe ( "ProviderTransform.options - gpt-5 textVerbosity" , ( ) = > {
const sessionID = "test-session-123"
const createGpt5Model = ( apiId : string ) = >
( {
id : ` openai/ ${ apiId } ` ,
providerID : "openai" ,
api : {
id : apiId ,
url : "https://api.openai.com" ,
npm : "@ai-sdk/openai" ,
} ,
name : apiId ,
capabilities : {
temperature : true ,
reasoning : true ,
attachment : true ,
toolcall : true ,
input : { text : true , audio : false , image : true , video : false , pdf : false } ,
output : { text : true , audio : false , image : false , video : false , pdf : false } ,
interleaved : false ,
} ,
cost : { input : 0.03 , output : 0.06 , cache : { read : 0.001 , write : 0.002 } } ,
limit : { context : 128000 , output : 4096 } ,
status : "active" ,
options : { } ,
headers : { } ,
} ) as any
test ( "gpt-5.2 should have textVerbosity set to low" , ( ) = > {
const model = createGpt5Model ( "gpt-5.2" )
const result = ProviderTransform . options ( { model , sessionID , providerOptions : { } } )
expect ( result . textVerbosity ) . toBe ( "low" )
} )
test ( "gpt-5.1 should have textVerbosity set to low" , ( ) = > {
const model = createGpt5Model ( "gpt-5.1" )
const result = ProviderTransform . options ( { model , sessionID , providerOptions : { } } )
expect ( result . textVerbosity ) . toBe ( "low" )
} )
test ( "gpt-5.2-chat-latest should NOT have textVerbosity set (only supports medium)" , ( ) = > {
const model = createGpt5Model ( "gpt-5.2-chat-latest" )
const result = ProviderTransform . options ( { model , sessionID , providerOptions : { } } )
expect ( result . textVerbosity ) . toBeUndefined ( )
} )
test ( "gpt-5.1-chat-latest should NOT have textVerbosity set (only supports medium)" , ( ) = > {
const model = createGpt5Model ( "gpt-5.1-chat-latest" )
const result = ProviderTransform . options ( { model , sessionID , providerOptions : { } } )
expect ( result . textVerbosity ) . toBeUndefined ( )
} )
test ( "gpt-5.2-chat should NOT have textVerbosity set" , ( ) = > {
const model = createGpt5Model ( "gpt-5.2-chat" )
const result = ProviderTransform . options ( { model , sessionID , providerOptions : { } } )
expect ( result . textVerbosity ) . toBeUndefined ( )
} )
test ( "gpt-5-chat should NOT have textVerbosity set" , ( ) = > {
const model = createGpt5Model ( "gpt-5-chat" )
const result = ProviderTransform . options ( { model , sessionID , providerOptions : { } } )
expect ( result . textVerbosity ) . toBeUndefined ( )
} )
test ( "gpt-5.2-codex should NOT have textVerbosity set (codex models excluded)" , ( ) = > {
const model = createGpt5Model ( "gpt-5.2-codex" )
const result = ProviderTransform . options ( { model , sessionID , providerOptions : { } } )
expect ( result . textVerbosity ) . toBeUndefined ( )
} )
} )
2026-02-14 18:32:29 +00:00
describe ( "ProviderTransform.options - gateway" , ( ) = > {
const sessionID = "test-session-123"
const createModel = ( id : string ) = >
( {
id ,
providerID : "vercel" ,
api : {
id ,
url : "https://ai-gateway.vercel.sh/v3/ai" ,
npm : "@ai-sdk/gateway" ,
} ,
name : id ,
capabilities : {
temperature : true ,
reasoning : true ,
attachment : true ,
toolcall : true ,
input : { text : true , audio : false , image : true , video : false , pdf : true } ,
output : { text : true , audio : false , image : false , video : false , pdf : false } ,
interleaved : false ,
} ,
cost : {
input : 0.001 ,
output : 0.002 ,
cache : { read : 0.0001 , write : 0.0002 } ,
} ,
limit : {
context : 200_000 ,
output : 8192 ,
} ,
status : "active" ,
options : { } ,
headers : { } ,
release_date : "2024-01-01" ,
} ) as any
test ( "puts gateway defaults under gateway key" , ( ) = > {
const model = createModel ( "anthropic/claude-sonnet-4" )
const result = ProviderTransform . options ( { model , sessionID , providerOptions : { } } )
expect ( result ) . toEqual ( {
gateway : {
caching : "auto" ,
} ,
} )
} )
} )
describe ( "ProviderTransform.providerOptions" , ( ) = > {
const createModel = ( overrides : Partial < any > = { } ) = >
( {
id : "test/test-model" ,
providerID : "test" ,
api : {
id : "test-model" ,
url : "https://api.test.com" ,
npm : "@ai-sdk/openai" ,
} ,
name : "Test Model" ,
capabilities : {
temperature : true ,
reasoning : true ,
attachment : true ,
toolcall : true ,
input : { text : true , audio : false , image : true , video : false , pdf : false } ,
output : { text : true , audio : false , image : false , video : false , pdf : false } ,
interleaved : false ,
} ,
cost : {
input : 0.001 ,
output : 0.002 ,
cache : { read : 0.0001 , write : 0.0002 } ,
} ,
limit : {
context : 200_000 ,
output : 64_000 ,
} ,
status : "active" ,
options : { } ,
headers : { } ,
release_date : "2024-01-01" ,
. . . overrides ,
} ) as any
test ( "uses sdk key for non-gateway models" , ( ) = > {
const model = createModel ( {
providerID : "my-bedrock" ,
api : {
id : "anthropic.claude-sonnet-4" ,
url : "https://bedrock.aws" ,
npm : "@ai-sdk/amazon-bedrock" ,
} ,
} )
expect ( ProviderTransform . providerOptions ( model , { cachePoint : { type : "default" } } ) ) . toEqual ( {
bedrock : { cachePoint : { type : "default" } } ,
} )
} )
test ( "uses gateway model provider slug for gateway models" , ( ) = > {
const model = createModel ( {
providerID : "vercel" ,
api : {
id : "anthropic/claude-sonnet-4" ,
url : "https://ai-gateway.vercel.sh/v3/ai" ,
npm : "@ai-sdk/gateway" ,
} ,
} )
expect ( ProviderTransform . providerOptions ( model , { thinking : { type : "enabled" , budgetTokens : 12_000 } } ) ) . toEqual ( {
anthropic : { thinking : { type : "enabled" , budgetTokens : 12_000 } } ,
} )
} )
test ( "falls back to gateway key when gateway api id is unscoped" , ( ) = > {
const model = createModel ( {
id : "anthropic/claude-sonnet-4" ,
providerID : "vercel" ,
api : {
id : "claude-sonnet-4" ,
url : "https://ai-gateway.vercel.sh/v3/ai" ,
npm : "@ai-sdk/gateway" ,
} ,
} )
expect ( ProviderTransform . providerOptions ( model , { thinking : { type : "enabled" , budgetTokens : 12_000 } } ) ) . toEqual ( {
gateway : { thinking : { type : "enabled" , budgetTokens : 12_000 } } ,
} )
} )
test ( "splits gateway routing options from provider-specific options" , ( ) = > {
const model = createModel ( {
providerID : "vercel" ,
api : {
id : "anthropic/claude-sonnet-4" ,
url : "https://ai-gateway.vercel.sh/v3/ai" ,
npm : "@ai-sdk/gateway" ,
} ,
} )
expect (
ProviderTransform . providerOptions ( model , {
gateway : { order : [ "vertex" , "anthropic" ] } ,
thinking : { type : "enabled" , budgetTokens : 12_000 } ,
} ) ,
) . toEqual ( {
gateway : { order : [ "vertex" , "anthropic" ] } ,
anthropic : { thinking : { type : "enabled" , budgetTokens : 12_000 } } ,
} as any )
} )
test ( "falls back to gateway key when model id has no provider slug" , ( ) = > {
const model = createModel ( {
id : "claude-sonnet-4" ,
providerID : "vercel" ,
api : {
id : "claude-sonnet-4" ,
url : "https://ai-gateway.vercel.sh/v3/ai" ,
npm : "@ai-sdk/gateway" ,
} ,
} )
expect ( ProviderTransform . providerOptions ( model , { reasoningEffort : "high" } ) ) . toEqual ( {
gateway : { reasoningEffort : "high" } ,
} )
} )
2026-02-14 19:18:52 +00:00
test ( "maps amazon slug to bedrock for provider options" , ( ) = > {
const model = createModel ( {
providerID : "vercel" ,
api : {
id : "amazon/nova-2-lite" ,
url : "https://ai-gateway.vercel.sh/v3/ai" ,
npm : "@ai-sdk/gateway" ,
} ,
} )
expect ( ProviderTransform . providerOptions ( model , { reasoningConfig : { type : "enabled" } } ) ) . toEqual ( {
bedrock : { reasoningConfig : { type : "enabled" } } ,
} )
} )
test ( "uses groq slug for groq models" , ( ) = > {
const model = createModel ( {
providerID : "vercel" ,
api : {
id : "groq/llama-3.3-70b-versatile" ,
url : "https://ai-gateway.vercel.sh/v3/ai" ,
npm : "@ai-sdk/gateway" ,
} ,
} )
expect ( ProviderTransform . providerOptions ( model , { reasoningFormat : "parsed" } ) ) . toEqual ( {
groq : { reasoningFormat : "parsed" } ,
} )
} )
2026-02-14 18:32:29 +00:00
} )
2025-12-20 17:41:52 +00:00
describe ( "ProviderTransform.schema - gemini array items" , ( ) = > {
test ( "adds missing items for array properties" , ( ) = > {
const geminiModel = {
providerID : "google" ,
api : {
id : "gemini-3-pro" ,
} ,
} as any
const schema = {
type : "object" ,
properties : {
nodes : { type : "array" } ,
edges : { type : "array" , items : { type : "string" } } ,
} ,
} as any
const result = ProviderTransform . schema ( geminiModel , schema ) as any
expect ( result . properties . nodes . items ) . toBeDefined ( )
expect ( result . properties . edges . items . type ) . toBe ( "string" )
} )
} )
2026-02-03 15:24:52 +00:00
describe ( "ProviderTransform.schema - gemini nested array items" , ( ) = > {
const geminiModel = {
providerID : "google" ,
api : {
id : "gemini-3-pro" ,
} ,
} as any
test ( "adds type to 2D array with empty inner items" , ( ) = > {
const schema = {
type : "object" ,
properties : {
values : {
type : "array" ,
items : {
type : "array" ,
items : { } , // Empty items object
} ,
} ,
} ,
} as any
const result = ProviderTransform . schema ( geminiModel , schema ) as any
// Inner items should have a default type
expect ( result . properties . values . items . items . type ) . toBe ( "string" )
} )
test ( "adds items and type to 2D array with missing inner items" , ( ) = > {
const schema = {
type : "object" ,
properties : {
data : {
type : "array" ,
items : { type : "array" } , // No items at all
} ,
} ,
} as any
const result = ProviderTransform . schema ( geminiModel , schema ) as any
expect ( result . properties . data . items . items ) . toBeDefined ( )
expect ( result . properties . data . items . items . type ) . toBe ( "string" )
} )
test ( "handles deeply nested arrays (3D)" , ( ) = > {
const schema = {
type : "object" ,
properties : {
matrix : {
type : "array" ,
items : {
type : "array" ,
items : {
type : "array" ,
// No items
} ,
} ,
} ,
} ,
} as any
const result = ProviderTransform . schema ( geminiModel , schema ) as any
expect ( result . properties . matrix . items . items . items ) . toBeDefined ( )
expect ( result . properties . matrix . items . items . items . type ) . toBe ( "string" )
} )
test ( "preserves existing item types in nested arrays" , ( ) = > {
const schema = {
type : "object" ,
properties : {
numbers : {
type : "array" ,
items : {
type : "array" ,
items : { type : "number" } , // Has explicit type
} ,
} ,
} ,
} as any
const result = ProviderTransform . schema ( geminiModel , schema ) as any
// Should preserve the explicit type
expect ( result . properties . numbers . items . items . type ) . toBe ( "number" )
} )
test ( "handles mixed nested structures with objects and arrays" , ( ) = > {
const schema = {
type : "object" ,
properties : {
spreadsheetData : {
type : "object" ,
properties : {
rows : {
type : "array" ,
items : {
type : "array" ,
items : { } , // Empty items
} ,
} ,
} ,
} ,
} ,
} as any
const result = ProviderTransform . schema ( geminiModel , schema ) as any
expect ( result . properties . spreadsheetData . properties . rows . items . items . type ) . toBe ( "string" )
} )
} )
2026-03-03 04:41:05 +00:00
describe ( "ProviderTransform.schema - gemini combiner nodes" , ( ) = > {
const geminiModel = {
providerID : "google" ,
api : {
id : "gemini-3-pro" ,
} ,
} as any
const walk = ( node : any , cb : ( node : any , path : ( string | number ) [ ] ) = > void , path : ( string | number ) [ ] = [ ] ) = > {
if ( node === null || typeof node !== "object" ) {
return
}
if ( Array . isArray ( node ) ) {
node . forEach ( ( item , i ) = > walk ( item , cb , [ . . . path , i ] ) )
return
}
cb ( node , path )
Object . entries ( node ) . forEach ( ( [ key , value ] ) = > walk ( value , cb , [ . . . path , key ] ) )
}
test ( "keeps edits.items.anyOf without adding type" , ( ) = > {
const schema = {
type : "object" ,
properties : {
edits : {
type : "array" ,
items : {
anyOf : [
{
type : "object" ,
properties : {
old_string : { type : "string" } ,
new_string : { type : "string" } ,
} ,
required : [ "old_string" , "new_string" ] ,
} ,
{
type : "object" ,
properties : {
old_string : { type : "string" } ,
new_string : { type : "string" } ,
replace_all : { type : "boolean" } ,
} ,
required : [ "old_string" , "new_string" ] ,
} ,
] ,
} ,
} ,
} ,
required : [ "edits" ] ,
} as any
const result = ProviderTransform . schema ( geminiModel , schema ) as any
expect ( Array . isArray ( result . properties . edits . items . anyOf ) ) . toBe ( true )
expect ( result . properties . edits . items . type ) . toBeUndefined ( )
} )
test ( "does not add sibling keys to combiner nodes during sanitize" , ( ) = > {
const schema = {
type : "object" ,
properties : {
edits : {
type : "array" ,
items : {
anyOf : [ { type : "string" } , { type : "number" } ] ,
} ,
} ,
value : {
oneOf : [ { type : "string" } , { type : "boolean" } ] ,
} ,
meta : {
allOf : [
{
type : "object" ,
properties : { a : { type : "string" } } ,
} ,
{
type : "object" ,
properties : { b : { type : "string" } } ,
} ,
] ,
} ,
} ,
} as any
const input = JSON . parse ( JSON . stringify ( schema ) )
const result = ProviderTransform . schema ( geminiModel , schema ) as any
walk ( result , ( node , path ) = > {
const hasCombiner = Array . isArray ( node . anyOf ) || Array . isArray ( node . oneOf ) || Array . isArray ( node . allOf )
if ( ! hasCombiner ) {
return
}
const before = path . reduce ( ( acc : any , key ) = > acc ? . [ key ] , input )
const added = Object . keys ( node ) . filter ( ( key ) = > ! ( key in before ) )
expect ( added ) . toEqual ( [ ] )
} )
} )
} )
2026-02-03 05:13:24 +00:00
describe ( "ProviderTransform.schema - gemini non-object properties removal" , ( ) = > {
const geminiModel = {
providerID : "google" ,
api : {
id : "gemini-3-pro" ,
} ,
} as any
test ( "removes properties from non-object types" , ( ) = > {
const schema = {
type : "object" ,
properties : {
data : {
type : "string" ,
properties : { invalid : { type : "string" } } ,
} ,
} ,
} as any
const result = ProviderTransform . schema ( geminiModel , schema ) as any
expect ( result . properties . data . type ) . toBe ( "string" )
expect ( result . properties . data . properties ) . toBeUndefined ( )
} )
test ( "removes required from non-object types" , ( ) = > {
const schema = {
type : "object" ,
properties : {
data : {
type : "array" ,
items : { type : "string" } ,
required : [ "invalid" ] ,
} ,
} ,
} as any
const result = ProviderTransform . schema ( geminiModel , schema ) as any
expect ( result . properties . data . type ) . toBe ( "array" )
expect ( result . properties . data . required ) . toBeUndefined ( )
} )
test ( "removes properties and required from nested non-object types" , ( ) = > {
const schema = {
type : "object" ,
properties : {
outer : {
type : "object" ,
properties : {
inner : {
type : "number" ,
properties : { bad : { type : "string" } } ,
required : [ "bad" ] ,
} ,
} ,
} ,
} ,
} as any
const result = ProviderTransform . schema ( geminiModel , schema ) as any
expect ( result . properties . outer . properties . inner . type ) . toBe ( "number" )
expect ( result . properties . outer . properties . inner . properties ) . toBeUndefined ( )
expect ( result . properties . outer . properties . inner . required ) . toBeUndefined ( )
} )
test ( "keeps properties and required on object types" , ( ) = > {
const schema = {
type : "object" ,
properties : {
data : {
type : "object" ,
properties : { name : { type : "string" } } ,
required : [ "name" ] ,
} ,
} ,
} as any
const result = ProviderTransform . schema ( geminiModel , schema ) as any
expect ( result . properties . data . type ) . toBe ( "object" )
expect ( result . properties . data . properties ) . toBeDefined ( )
expect ( result . properties . data . required ) . toEqual ( [ "name" ] )
} )
test ( "does not affect non-gemini providers" , ( ) = > {
const openaiModel = {
providerID : "openai" ,
api : {
id : "gpt-4" ,
} ,
} as any
const schema = {
type : "object" ,
properties : {
data : {
type : "string" ,
properties : { invalid : { type : "string" } } ,
} ,
} ,
} as any
const result = ProviderTransform . schema ( openaiModel , schema ) as any
expect ( result . properties . data . properties ) . toBeDefined ( )
} )
} )
2026-04-28 04:44:21 +00:00
describe ( "ProviderTransform.schema - moonshot $ref siblings" , ( ) = > {
const moonshotModel = {
providerID : "moonshotai" ,
api : {
id : "kimi-k2" ,
} ,
} as any
test ( "removes sibling descriptions from referenced tool parameter schemas" , ( ) = > {
const schema = {
type : "object" ,
properties : {
deviceType : {
description : "Optional. The type of device that captured the screenshot, e.g. mobile or desktop." ,
enum : [ "DEVICE_TYPE_UNSPECIFIED" , "MOBILE" , "DESKTOP" , "TABLET" , "AGNOSTIC" ] ,
type : "string" ,
} ,
modelId : {
description : "Optional. The model to use for generation." ,
enum : [ "MODEL_ID_UNSPECIFIED" , "GEMINI_3_PRO" , "GEMINI_3_FLASH" , "GEMINI_3_1_PRO" ] ,
type : "string" ,
} ,
projectId : {
description : "Required. The project ID of screens to generate variants for." ,
type : "string" ,
} ,
prompt : {
description : "Required. The input text used to generate the variants." ,
type : "string" ,
} ,
selectedScreenIds : {
description : "Required. The screen ids of screen to generate variants for." ,
items : {
type : "string" ,
} ,
type : "array" ,
} ,
variantOptions : {
$ref : "#/$defs/VariantOptions" ,
description :
"Required. The variant options for generation, including the number of variants, creative range, and aspects to focus on." ,
} ,
} ,
required : [ "projectId" , "selectedScreenIds" , "prompt" , "variantOptions" ] ,
$defs : {
VariantOptions : {
description :
"Configuration options for design variant generation. This message captures all parameters used to generate variants, allowing the configuration to be stored, replayed, or analyzed." ,
properties : {
aspects : {
description : "Optional. Specific aspects to focus on. If empty, all aspects may be varied." ,
items : {
2026-04-28 04:45:24 +00:00
enum : [ "VARIANT_ASPECT_UNSPECIFIED" , "LAYOUT" , "COLOR_SCHEME" , "IMAGES" , "TEXT_FONT" , "TEXT_CONTENT" ] ,
2026-04-28 04:44:21 +00:00
type : "string" ,
} ,
type : "array" ,
} ,
creativeRange : {
description : "Optional. Creative range for variations. Default: EXPLORE" ,
enum : [ "CREATIVE_RANGE_UNSPECIFIED" , "REFINE" , "EXPLORE" , "REIMAGINE" ] ,
type : "string" ,
} ,
variantCount : {
description : "Optional. Number of variants to generate (1-5). Default: 3" ,
format : "int32" ,
type : "integer" ,
} ,
} ,
type : "object" ,
} ,
} ,
description : "Request message for GenerateVariants." ,
additionalProperties : false ,
} as any
const result = ProviderTransform . schema ( moonshotModel , schema ) as any
expect ( result . properties . variantOptions ) . toEqual ( {
$ref : "#/$defs/VariantOptions" ,
} )
expect ( result . $defs . VariantOptions . description ) . toBe ( schema . $defs . VariantOptions . description )
} )
test ( "also runs for kimi models outside the moonshot provider" , ( ) = > {
const result = ProviderTransform . schema (
{
providerID : "openrouter" ,
name : "Kimi K2" ,
api : {
id : "moonshotai/kimi-k2" ,
} ,
} as any ,
{
type : "object" ,
properties : {
value : {
$ref : "#/$defs/Value" ,
description : "Moonshot rejects this sibling after ref expansion." ,
} ,
} ,
$defs : {
Value : {
description : "Referenced schema description stays here." ,
type : "object" ,
} ,
} ,
} as any ,
) as any
expect ( result . properties . value ) . toEqual ( {
$ref : "#/$defs/Value" ,
} )
} )
test ( "converts tuple-style array items to a single item schema" , ( ) = > {
2026-04-28 04:45:24 +00:00
const result = ProviderTransform . schema ( moonshotModel , {
type : "object" ,
properties : {
codeSpec : {
type : "object" ,
properties : {
accessibility : {
type : "object" ,
properties : {
renderedSize : {
description : "Rendered size [width, height] in px" ,
type : "array" ,
items : [ { type : "number" } , { type : "number" } ] ,
minItems : 2 ,
maxItems : 2 ,
2026-04-28 04:44:21 +00:00
} ,
} ,
} ,
} ,
} ,
2026-04-28 04:45:24 +00:00
} ,
} as any ) as any
2026-04-28 04:44:21 +00:00
expect ( result . properties . codeSpec . properties . accessibility . properties . renderedSize . items ) . toEqual ( {
type : "number" ,
} )
} )
} )
2025-12-04 03:31:36 +00:00
describe ( "ProviderTransform.message - DeepSeek reasoning content" , ( ) = > {
test ( "DeepSeek with tool calls includes reasoning_content in providerOptions" , ( ) = > {
const msgs = [
{
role : "assistant" ,
content : [
{ type : "reasoning" , text : "Let me think about this..." } ,
{
type : "tool-call" ,
toolCallId : "test" ,
toolName : "bash" ,
input : { command : "echo hello" } ,
} ,
] ,
} ,
] as any [ ]
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . message (
msgs ,
{
2026-03-12 13:27:52 +00:00
id : ModelID.make ( "deepseek/deepseek-chat" ) ,
providerID : ProviderID.make ( "deepseek" ) ,
2026-01-15 07:31:50 +00:00
api : {
id : "deepseek-chat" ,
url : "https://api.deepseek.com" ,
npm : "@ai-sdk/openai-compatible" ,
2025-12-19 22:37:36 +00:00
} ,
2026-01-15 07:31:50 +00:00
name : "DeepSeek Chat" ,
capabilities : {
temperature : true ,
reasoning : true ,
attachment : false ,
toolcall : true ,
input : { text : true , audio : false , image : false , video : false , pdf : false } ,
output : { text : true , audio : false , image : false , video : false , pdf : false } ,
interleaved : {
field : "reasoning_content" ,
} ,
} ,
cost : {
input : 0.001 ,
output : 0.002 ,
cache : { read : 0.0001 , write : 0.0002 } ,
} ,
limit : {
context : 128000 ,
output : 8192 ,
} ,
status : "active" ,
options : { } ,
headers : { } ,
release_date : "2023-04-01" ,
2025-12-04 03:31:36 +00:00
} ,
2026-01-15 07:31:50 +00:00
{ } ,
)
2025-12-04 03:31:36 +00:00
expect ( result ) . toHaveLength ( 1 )
expect ( result [ 0 ] . content ) . toEqual ( [
{
type : "tool-call" ,
toolCallId : "test" ,
toolName : "bash" ,
input : { command : "echo hello" } ,
} ,
] )
expect ( result [ 0 ] . providerOptions ? . openaiCompatible ? . reasoning_content ) . toBe ( "Let me think about this..." )
} )
test ( "Non-DeepSeek providers leave reasoning content unchanged" , ( ) = > {
const msgs = [
{
role : "assistant" ,
content : [
{ type : "reasoning" , text : "Should not be processed" } ,
{ type : "text" , text : "Answer" } ,
] ,
} ,
] as any [ ]
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . message (
msgs ,
{
2026-03-12 13:27:52 +00:00
id : ModelID.make ( "openai/gpt-4" ) ,
providerID : ProviderID.make ( "openai" ) ,
2026-01-15 07:31:50 +00:00
api : {
id : "gpt-4" ,
url : "https://api.openai.com" ,
npm : "@ai-sdk/openai" ,
} ,
name : "GPT-4" ,
capabilities : {
temperature : true ,
reasoning : false ,
attachment : true ,
toolcall : true ,
input : { text : true , audio : false , image : true , video : false , pdf : false } ,
output : { text : true , audio : false , image : false , video : false , pdf : false } ,
interleaved : false ,
} ,
cost : {
input : 0.03 ,
output : 0.06 ,
cache : { read : 0.001 , write : 0.002 } ,
} ,
limit : {
context : 128000 ,
output : 4096 ,
} ,
status : "active" ,
options : { } ,
headers : { } ,
release_date : "2023-04-01" ,
2025-12-04 03:31:36 +00:00
} ,
2026-01-15 07:31:50 +00:00
{ } ,
)
2025-12-04 03:31:36 +00:00
expect ( result [ 0 ] . content ) . toEqual ( [
{ type : "reasoning" , text : "Should not be processed" } ,
{ type : "text" , text : "Answer" } ,
] )
expect ( result [ 0 ] . providerOptions ? . openaiCompatible ? . reasoning_content ) . toBeUndefined ( )
} )
} )
2025-12-15 05:56:47 +00:00
describe ( "ProviderTransform.message - empty image handling" , ( ) = > {
const mockModel = {
id : "anthropic/claude-3-5-sonnet" ,
providerID : "anthropic" ,
api : {
id : "claude-3-5-sonnet-20241022" ,
url : "https://api.anthropic.com" ,
npm : "@ai-sdk/anthropic" ,
} ,
name : "Claude 3.5 Sonnet" ,
capabilities : {
temperature : true ,
reasoning : false ,
attachment : true ,
toolcall : true ,
input : { text : true , audio : false , image : true , video : false , pdf : true } ,
output : { text : true , audio : false , image : false , video : false , pdf : false } ,
interleaved : false ,
} ,
cost : {
input : 0.003 ,
output : 0.015 ,
cache : { read : 0.0003 , write : 0.00375 } ,
} ,
limit : {
context : 200000 ,
output : 8192 ,
} ,
status : "active" ,
options : { } ,
headers : { } ,
} as any
test ( "should replace empty base64 image with error text" , ( ) = > {
const msgs = [
{
role : "user" ,
content : [
{ type : "text" , text : "What is in this image?" } ,
{ type : "image" , image : "data:image/png;base64," } ,
] ,
} ,
] as any [ ]
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . message ( msgs , mockModel , { } )
2025-12-15 05:56:47 +00:00
expect ( result ) . toHaveLength ( 1 )
expect ( result [ 0 ] . content ) . toHaveLength ( 2 )
expect ( result [ 0 ] . content [ 0 ] ) . toEqual ( { type : "text" , text : "What is in this image?" } )
expect ( result [ 0 ] . content [ 1 ] ) . toEqual ( {
type : "text" ,
text : "ERROR: Image file is empty or corrupted. Please provide a valid image." ,
} )
} )
test ( "should keep valid base64 images unchanged" , ( ) = > {
const validBase64 =
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
const msgs = [
{
role : "user" ,
content : [
{ type : "text" , text : "What is in this image?" } ,
{ type : "image" , image : ` data:image/png;base64, ${ validBase64 } ` } ,
] ,
} ,
] as any [ ]
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . message ( msgs , mockModel , { } )
2025-12-15 05:56:47 +00:00
expect ( result ) . toHaveLength ( 1 )
expect ( result [ 0 ] . content ) . toHaveLength ( 2 )
expect ( result [ 0 ] . content [ 0 ] ) . toEqual ( { type : "text" , text : "What is in this image?" } )
expect ( result [ 0 ] . content [ 1 ] ) . toEqual ( { type : "image" , image : ` data:image/png;base64, ${ validBase64 } ` } )
} )
test ( "should handle mixed valid and empty images" , ( ) = > {
const validBase64 =
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
const msgs = [
{
role : "user" ,
content : [
{ type : "text" , text : "Compare these images" } ,
{ type : "image" , image : ` data:image/png;base64, ${ validBase64 } ` } ,
{ type : "image" , image : "data:image/jpeg;base64," } ,
] ,
} ,
] as any [ ]
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . message ( msgs , mockModel , { } )
2025-12-15 05:56:47 +00:00
expect ( result ) . toHaveLength ( 1 )
expect ( result [ 0 ] . content ) . toHaveLength ( 3 )
expect ( result [ 0 ] . content [ 0 ] ) . toEqual ( { type : "text" , text : "Compare these images" } )
expect ( result [ 0 ] . content [ 1 ] ) . toEqual ( { type : "image" , image : ` data:image/png;base64, ${ validBase64 } ` } )
expect ( result [ 0 ] . content [ 2 ] ) . toEqual ( {
type : "text" ,
text : "ERROR: Image file is empty or corrupted. Please provide a valid image." ,
} )
} )
} )
2025-12-30 22:37:32 +00:00
2026-01-05 07:18:46 +00:00
describe ( "ProviderTransform.message - anthropic empty content filtering" , ( ) = > {
const anthropicModel = {
id : "anthropic/claude-3-5-sonnet" ,
providerID : "anthropic" ,
api : {
id : "claude-3-5-sonnet-20241022" ,
url : "https://api.anthropic.com" ,
npm : "@ai-sdk/anthropic" ,
} ,
name : "Claude 3.5 Sonnet" ,
capabilities : {
temperature : true ,
reasoning : false ,
attachment : true ,
toolcall : true ,
input : { text : true , audio : false , image : true , video : false , pdf : true } ,
output : { text : true , audio : false , image : false , video : false , pdf : false } ,
interleaved : false ,
} ,
cost : {
input : 0.003 ,
output : 0.015 ,
cache : { read : 0.0003 , write : 0.00375 } ,
} ,
limit : {
context : 200000 ,
output : 8192 ,
} ,
status : "active" ,
options : { } ,
headers : { } ,
} as any
test ( "filters out messages with empty string content" , ( ) = > {
const msgs = [
{ role : "user" , content : "Hello" } ,
{ role : "assistant" , content : "" } ,
{ role : "user" , content : "World" } ,
] as any [ ]
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . message ( msgs , anthropicModel , { } )
2026-01-05 07:18:46 +00:00
expect ( result ) . toHaveLength ( 2 )
expect ( result [ 0 ] . content ) . toBe ( "Hello" )
expect ( result [ 1 ] . content ) . toBe ( "World" )
} )
test ( "filters out empty text parts from array content" , ( ) = > {
const msgs = [
{
role : "assistant" ,
content : [
{ type : "text" , text : "" } ,
{ type : "text" , text : "Hello" } ,
{ type : "text" , text : "" } ,
] ,
} ,
] as any [ ]
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . message ( msgs , anthropicModel , { } )
2026-01-05 07:18:46 +00:00
expect ( result ) . toHaveLength ( 1 )
expect ( result [ 0 ] . content ) . toHaveLength ( 1 )
expect ( result [ 0 ] . content [ 0 ] ) . toEqual ( { type : "text" , text : "Hello" } )
} )
test ( "filters out empty reasoning parts from array content" , ( ) = > {
const msgs = [
{
role : "assistant" ,
content : [
{ type : "reasoning" , text : "" } ,
{ type : "text" , text : "Answer" } ,
{ type : "reasoning" , text : "" } ,
] ,
} ,
] as any [ ]
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . message ( msgs , anthropicModel , { } )
2026-01-05 07:18:46 +00:00
expect ( result ) . toHaveLength ( 1 )
expect ( result [ 0 ] . content ) . toHaveLength ( 1 )
expect ( result [ 0 ] . content [ 0 ] ) . toEqual ( { type : "text" , text : "Answer" } )
} )
test ( "removes entire message when all parts are empty" , ( ) = > {
const msgs = [
{ role : "user" , content : "Hello" } ,
{
role : "assistant" ,
content : [
{ type : "text" , text : "" } ,
{ type : "reasoning" , text : "" } ,
] ,
} ,
{ role : "user" , content : "World" } ,
] as any [ ]
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . message ( msgs , anthropicModel , { } )
2026-01-05 07:18:46 +00:00
expect ( result ) . toHaveLength ( 2 )
expect ( result [ 0 ] . content ) . toBe ( "Hello" )
expect ( result [ 1 ] . content ) . toBe ( "World" )
} )
test ( "keeps non-text/reasoning parts even if text parts are empty" , ( ) = > {
const msgs = [
{
role : "assistant" ,
content : [
{ type : "text" , text : "" } ,
{ type : "tool-call" , toolCallId : "123" , toolName : "bash" , input : { command : "ls" } } ,
] ,
} ,
] as any [ ]
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . message ( msgs , anthropicModel , { } )
2026-01-05 07:18:46 +00:00
expect ( result ) . toHaveLength ( 1 )
expect ( result [ 0 ] . content ) . toHaveLength ( 1 )
expect ( result [ 0 ] . content [ 0 ] ) . toEqual ( {
type : "tool-call" ,
toolCallId : "123" ,
toolName : "bash" ,
input : { command : "ls" } ,
} )
} )
test ( "keeps messages with valid text alongside empty parts" , ( ) = > {
const msgs = [
{
role : "assistant" ,
content : [
{ type : "reasoning" , text : "Thinking..." } ,
{ type : "text" , text : "" } ,
{ type : "text" , text : "Result" } ,
] ,
} ,
] as any [ ]
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . message ( msgs , anthropicModel , { } )
2026-01-05 07:18:46 +00:00
expect ( result ) . toHaveLength ( 1 )
expect ( result [ 0 ] . content ) . toHaveLength ( 2 )
expect ( result [ 0 ] . content [ 0 ] ) . toEqual ( { type : "reasoning" , text : "Thinking..." } )
expect ( result [ 0 ] . content [ 1 ] ) . toEqual ( { type : "text" , text : "Result" } )
} )
2026-03-13 03:13:09 +00:00
test ( "filters empty content for bedrock provider" , ( ) = > {
const bedrockModel = {
. . . anthropicModel ,
id : "amazon-bedrock/anthropic.claude-opus-4-6" ,
providerID : "amazon-bedrock" ,
api : {
id : "anthropic.claude-opus-4-6" ,
url : "https://bedrock-runtime.us-east-1.amazonaws.com" ,
npm : "@ai-sdk/amazon-bedrock" ,
} ,
}
const msgs = [
{ role : "user" , content : "Hello" } ,
{ role : "assistant" , content : "" } ,
{
role : "assistant" ,
content : [
{ type : "text" , text : "" } ,
{ type : "text" , text : "Answer" } ,
] ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , bedrockModel , { } )
expect ( result ) . toHaveLength ( 2 )
expect ( result [ 0 ] . content ) . toBe ( "Hello" )
expect ( result [ 1 ] . content ) . toHaveLength ( 1 )
expect ( result [ 1 ] . content [ 0 ] ) . toEqual ( { type : "text" , text : "Answer" } )
} )
2026-01-05 07:18:46 +00:00
test ( "does not filter for non-anthropic providers" , ( ) = > {
const openaiModel = {
. . . anthropicModel ,
providerID : "openai" ,
api : {
id : "gpt-4" ,
url : "https://api.openai.com" ,
npm : "@ai-sdk/openai" ,
} ,
}
const msgs = [
{ role : "assistant" , content : "" } ,
{
role : "assistant" ,
content : [ { type : "text" , text : "" } ] ,
} ,
] as any [ ]
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . message ( msgs , openaiModel , { } )
2026-01-05 07:18:46 +00:00
expect ( result ) . toHaveLength ( 2 )
expect ( result [ 0 ] . content ) . toBe ( "" )
expect ( result [ 1 ] . content ) . toHaveLength ( 1 )
} )
2026-04-15 19:56:45 +00:00
test ( "splits anthropic assistant messages when text trails tool calls" , ( ) = > {
const msgs = [
{
role : "user" ,
content : [ { type : "text" , text : "Check my home directory for PDFs" } ] ,
} ,
{
role : "assistant" ,
content : [
{ type : "tool-call" , toolCallId : "toolu_1" , toolName : "read" , input : { filePath : "/root" } } ,
{ type : "tool-call" , toolCallId : "toolu_2" , toolName : "glob" , input : { pattern : "**/*.pdf" } } ,
{ type : "text" , text : "I checked your home directory and looked for PDF files." } ,
] ,
} ,
{
role : "tool" ,
content : [
{ type : "tool-result" , toolCallId : "toolu_1" , toolName : "read" , output : { type : "text" , value : "ok" } } ,
{
type : "tool-result" ,
toolCallId : "toolu_2" ,
toolName : "glob" ,
output : { type : "text" , value : "No files found" } ,
} ,
] ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , anthropicModel , { } ) as any [ ]
expect ( result ) . toHaveLength ( 4 )
expect ( result [ 1 ] ) . toMatchObject ( {
role : "assistant" ,
content : [ { type : "text" , text : "I checked your home directory and looked for PDF files." } ] ,
} )
expect ( result [ 2 ] ) . toMatchObject ( {
role : "assistant" ,
content : [
{ type : "tool-call" , toolCallId : "toolu_1" , toolName : "read" , input : { filePath : "/root" } } ,
{ type : "tool-call" , toolCallId : "toolu_2" , toolName : "glob" , input : { pattern : "**/*.pdf" } } ,
] ,
} )
} )
test ( "leaves valid anthropic assistant tool ordering unchanged" , ( ) = > {
const msgs = [
{
role : "assistant" ,
content : [
{ type : "text" , text : "I checked your home directory and looked for PDF files." } ,
{ type : "tool-call" , toolCallId : "toolu_1" , toolName : "read" , input : { filePath : "/root" } } ,
{ type : "tool-call" , toolCallId : "toolu_2" , toolName : "glob" , input : { pattern : "**/*.pdf" } } ,
] ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , anthropicModel , { } ) as any [ ]
expect ( result ) . toHaveLength ( 1 )
expect ( result [ 0 ] . content ) . toMatchObject ( [
{ type : "text" , text : "I checked your home directory and looked for PDF files." } ,
{ type : "tool-call" , toolCallId : "toolu_1" , toolName : "read" , input : { filePath : "/root" } } ,
{ type : "tool-call" , toolCallId : "toolu_2" , toolName : "glob" , input : { pattern : "**/*.pdf" } } ,
] )
} )
test ( "splits vertex anthropic assistant messages when text trails tool calls" , ( ) = > {
const model = {
. . . anthropicModel ,
providerID : "google-vertex-anthropic" ,
api : {
id : "claude-sonnet-4@20250514" ,
url : "https://us-central1-aiplatform.googleapis.com" ,
npm : "@ai-sdk/google-vertex/anthropic" ,
} ,
}
const msgs = [
{
role : "assistant" ,
content : [
{ type : "tool-call" , toolCallId : "toolu_1" , toolName : "read" , input : { filePath : "/root" } } ,
{ type : "tool-call" , toolCallId : "toolu_2" , toolName : "glob" , input : { pattern : "**/*.pdf" } } ,
{ type : "text" , text : "I checked your home directory and looked for PDF files." } ,
] ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , model , { } ) as any [ ]
expect ( result ) . toHaveLength ( 2 )
expect ( result [ 0 ] ) . toMatchObject ( {
role : "assistant" ,
content : [ { type : "text" , text : "I checked your home directory and looked for PDF files." } ] ,
} )
expect ( result [ 1 ] ) . toMatchObject ( {
role : "assistant" ,
content : [
{ type : "tool-call" , toolCallId : "toolu_1" , toolName : "read" , input : { filePath : "/root" } } ,
{ type : "tool-call" , toolCallId : "toolu_2" , toolName : "glob" , input : { pattern : "**/*.pdf" } } ,
] ,
} )
} )
2026-01-05 07:18:46 +00:00
} )
2026-01-15 07:31:50 +00:00
describe ( "ProviderTransform.message - strip openai metadata when store=false" , ( ) = > {
const openaiModel = {
id : "openai/gpt-5" ,
providerID : "openai" ,
api : {
id : "gpt-5" ,
url : "https://api.openai.com" ,
npm : "@ai-sdk/openai" ,
} ,
name : "GPT-5" ,
capabilities : {
temperature : true ,
reasoning : true ,
attachment : true ,
toolcall : true ,
input : { text : true , audio : false , image : true , video : false , pdf : false } ,
output : { text : true , audio : false , image : false , video : false , pdf : false } ,
interleaved : false ,
} ,
cost : { input : 0.03 , output : 0.06 , cache : { read : 0.001 , write : 0.002 } } ,
limit : { context : 128000 , output : 4096 } ,
status : "active" ,
options : { } ,
headers : { } ,
} as any
2026-01-17 04:09:36 +00:00
test ( "preserves itemId and reasoningEncryptedContent when store=false" , ( ) = > {
2026-01-15 07:31:50 +00:00
const msgs = [
{
role : "assistant" ,
content : [
{
type : "reasoning" ,
text : "thinking..." ,
providerOptions : {
openai : {
itemId : "rs_123" ,
reasoningEncryptedContent : "encrypted" ,
} ,
} ,
} ,
{
type : "text" ,
text : "Hello" ,
providerOptions : {
openai : {
itemId : "msg_456" ,
} ,
} ,
} ,
] ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , openaiModel , { store : false } ) as any [ ]
expect ( result ) . toHaveLength ( 1 )
2026-01-17 04:09:36 +00:00
expect ( result [ 0 ] . content [ 0 ] . providerOptions ? . openai ? . itemId ) . toBe ( "rs_123" )
expect ( result [ 0 ] . content [ 1 ] . providerOptions ? . openai ? . itemId ) . toBe ( "msg_456" )
2026-01-15 07:31:50 +00:00
} )
2026-01-17 04:09:36 +00:00
test ( "preserves itemId and reasoningEncryptedContent when store=false even when not openai" , ( ) = > {
2026-01-15 07:31:50 +00:00
const zenModel = {
. . . openaiModel ,
providerID : "zen" ,
}
const msgs = [
{
role : "assistant" ,
content : [
{
type : "reasoning" ,
text : "thinking..." ,
providerOptions : {
openai : {
itemId : "rs_123" ,
reasoningEncryptedContent : "encrypted" ,
} ,
} ,
} ,
{
type : "text" ,
text : "Hello" ,
providerOptions : {
openai : {
itemId : "msg_456" ,
} ,
} ,
} ,
] ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , zenModel , { store : false } ) as any [ ]
expect ( result ) . toHaveLength ( 1 )
2026-01-17 04:09:36 +00:00
expect ( result [ 0 ] . content [ 0 ] . providerOptions ? . openai ? . itemId ) . toBe ( "rs_123" )
expect ( result [ 0 ] . content [ 1 ] . providerOptions ? . openai ? . itemId ) . toBe ( "msg_456" )
2026-01-15 07:31:50 +00:00
} )
2026-01-17 04:09:36 +00:00
test ( "preserves other openai options including itemId" , ( ) = > {
2026-01-15 07:31:50 +00:00
const msgs = [
{
role : "assistant" ,
content : [
{
type : "text" ,
text : "Hello" ,
providerOptions : {
openai : {
itemId : "msg_123" ,
otherOption : "value" ,
} ,
} ,
} ,
] ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , openaiModel , { store : false } ) as any [ ]
2026-01-17 04:09:36 +00:00
expect ( result [ 0 ] . content [ 0 ] . providerOptions ? . openai ? . itemId ) . toBe ( "msg_123" )
2026-01-15 07:31:50 +00:00
expect ( result [ 0 ] . content [ 0 ] . providerOptions ? . openai ? . otherOption ) . toBe ( "value" )
} )
2026-01-17 04:09:36 +00:00
test ( "preserves metadata for openai package when store is true" , ( ) = > {
2026-01-15 07:31:50 +00:00
const msgs = [
{
role : "assistant" ,
content : [
{
type : "text" ,
text : "Hello" ,
providerOptions : {
openai : {
itemId : "msg_123" ,
} ,
} ,
} ,
] ,
} ,
] as any [ ]
2026-01-17 04:09:36 +00:00
// openai package preserves itemId regardless of store value
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . message ( msgs , openaiModel , { store : true } ) as any [ ]
2026-01-17 04:09:36 +00:00
expect ( result [ 0 ] . content [ 0 ] . providerOptions ? . openai ? . itemId ) . toBe ( "msg_123" )
2026-01-15 07:31:50 +00:00
} )
2026-01-17 04:09:36 +00:00
test ( "preserves metadata for non-openai packages when store is false" , ( ) = > {
2026-01-15 07:31:50 +00:00
const anthropicModel = {
. . . openaiModel ,
providerID : "anthropic" ,
api : {
id : "claude-3" ,
url : "https://api.anthropic.com" ,
npm : "@ai-sdk/anthropic" ,
} ,
}
const msgs = [
{
role : "assistant" ,
content : [
{
type : "text" ,
text : "Hello" ,
providerOptions : {
openai : {
itemId : "msg_123" ,
} ,
} ,
} ,
] ,
} ,
] as any [ ]
2026-01-17 04:09:36 +00:00
// store=false preserves metadata for non-openai packages
2026-01-15 07:31:50 +00:00
const result = ProviderTransform . message ( msgs , anthropicModel , { store : false } ) as any [ ]
2026-01-17 04:09:36 +00:00
expect ( result [ 0 ] . content [ 0 ] . providerOptions ? . openai ? . itemId ) . toBe ( "msg_123" )
2026-01-15 07:31:50 +00:00
} )
2026-01-17 04:09:36 +00:00
test ( "preserves metadata using providerID key when store is false" , ( ) = > {
2026-01-16 17:32:12 +00:00
const opencodeModel = {
. . . openaiModel ,
providerID : "opencode" ,
api : {
id : "opencode-test" ,
url : "https://api.opencode.ai" ,
npm : "@ai-sdk/openai-compatible" ,
} ,
}
const msgs = [
{
role : "assistant" ,
content : [
{
type : "text" ,
text : "Hello" ,
providerOptions : {
opencode : {
itemId : "msg_123" ,
otherOption : "value" ,
} ,
} ,
} ,
] ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , opencodeModel , { store : false } ) as any [ ]
2026-01-17 04:09:36 +00:00
expect ( result [ 0 ] . content [ 0 ] . providerOptions ? . opencode ? . itemId ) . toBe ( "msg_123" )
2026-01-16 17:32:12 +00:00
expect ( result [ 0 ] . content [ 0 ] . providerOptions ? . opencode ? . otherOption ) . toBe ( "value" )
} )
2026-01-17 04:09:36 +00:00
test ( "preserves itemId across all providerOptions keys" , ( ) = > {
2026-01-16 17:32:12 +00:00
const opencodeModel = {
. . . openaiModel ,
providerID : "opencode" ,
api : {
id : "opencode-test" ,
url : "https://api.opencode.ai" ,
npm : "@ai-sdk/openai-compatible" ,
} ,
}
const msgs = [
{
role : "assistant" ,
providerOptions : {
openai : { itemId : "msg_root" } ,
opencode : { itemId : "msg_opencode" } ,
extra : { itemId : "msg_extra" } ,
} ,
content : [
{
type : "text" ,
text : "Hello" ,
providerOptions : {
openai : { itemId : "msg_openai_part" } ,
opencode : { itemId : "msg_opencode_part" } ,
extra : { itemId : "msg_extra_part" } ,
} ,
} ,
] ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , opencodeModel , { store : false } ) as any [ ]
2026-01-17 04:09:36 +00:00
expect ( result [ 0 ] . providerOptions ? . openai ? . itemId ) . toBe ( "msg_root" )
expect ( result [ 0 ] . providerOptions ? . opencode ? . itemId ) . toBe ( "msg_opencode" )
expect ( result [ 0 ] . providerOptions ? . extra ? . itemId ) . toBe ( "msg_extra" )
expect ( result [ 0 ] . content [ 0 ] . providerOptions ? . openai ? . itemId ) . toBe ( "msg_openai_part" )
expect ( result [ 0 ] . content [ 0 ] . providerOptions ? . opencode ? . itemId ) . toBe ( "msg_opencode_part" )
expect ( result [ 0 ] . content [ 0 ] . providerOptions ? . extra ? . itemId ) . toBe ( "msg_extra_part" )
2026-01-16 17:32:12 +00:00
} )
2026-01-15 07:31:50 +00:00
test ( "does not strip metadata for non-openai packages when store is not false" , ( ) = > {
const anthropicModel = {
. . . openaiModel ,
providerID : "anthropic" ,
api : {
id : "claude-3" ,
url : "https://api.anthropic.com" ,
npm : "@ai-sdk/anthropic" ,
} ,
}
const msgs = [
{
role : "assistant" ,
content : [
{
type : "text" ,
text : "Hello" ,
providerOptions : {
openai : {
itemId : "msg_123" ,
} ,
} ,
} ,
] ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , anthropicModel , { } ) as any [ ]
expect ( result [ 0 ] . content [ 0 ] . providerOptions ? . openai ? . itemId ) . toBe ( "msg_123" )
} )
} )
2026-01-17 06:35:49 +00:00
describe ( "ProviderTransform.message - providerOptions key remapping" , ( ) = > {
const createModel = ( providerID : string , npm : string ) = >
( {
id : ` ${ providerID } /test-model ` ,
providerID ,
api : {
id : "test-model" ,
url : "https://api.test.com" ,
npm ,
} ,
name : "Test Model" ,
capabilities : {
temperature : true ,
reasoning : false ,
attachment : true ,
toolcall : true ,
input : { text : true , audio : false , image : true , video : false , pdf : true } ,
output : { text : true , audio : false , image : false , video : false , pdf : false } ,
interleaved : false ,
} ,
cost : { input : 0.001 , output : 0.002 , cache : { read : 0.0001 , write : 0.0002 } } ,
limit : { context : 128000 , output : 8192 } ,
status : "active" ,
options : { } ,
headers : { } ,
} ) as any
test ( "azure keeps 'azure' key and does not remap to 'openai'" , ( ) = > {
const model = createModel ( "azure" , "@ai-sdk/azure" )
const msgs = [
{
role : "user" ,
content : "Hello" ,
providerOptions : {
azure : { someOption : "value" } ,
} ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , model , { } )
expect ( result [ 0 ] . providerOptions ? . azure ) . toEqual ( { someOption : "value" } )
expect ( result [ 0 ] . providerOptions ? . openai ) . toBeUndefined ( )
} )
2026-03-31 19:57:15 +00:00
test ( "azure cognitive services remaps providerID to 'azure' key" , ( ) = > {
const model = createModel ( "azure-cognitive-services" , "@ai-sdk/azure" )
const msgs = [
{
role : "user" ,
content : [
{
type : "text" ,
text : "Hello" ,
providerOptions : {
"azure-cognitive-services" : { part : true } ,
} ,
} ,
] ,
providerOptions : {
"azure-cognitive-services" : { someOption : "value" } ,
} ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , model , { } ) as any [ ]
const part = result [ 0 ] . content [ 0 ] as any
expect ( result [ 0 ] . providerOptions ? . azure ) . toEqual ( { someOption : "value" } )
expect ( result [ 0 ] . providerOptions ? . [ "azure-cognitive-services" ] ) . toBeUndefined ( )
expect ( part . providerOptions ? . azure ) . toEqual ( { part : true } )
expect ( part . providerOptions ? . [ "azure-cognitive-services" ] ) . toBeUndefined ( )
} )
2026-01-31 01:53:22 +00:00
test ( "copilot remaps providerID to 'copilot' key" , ( ) = > {
2026-01-17 06:35:49 +00:00
const model = createModel ( "github-copilot" , "@ai-sdk/github-copilot" )
const msgs = [
{
role : "user" ,
content : "Hello" ,
providerOptions : {
2026-01-31 02:35:22 +00:00
copilot : { someOption : "value" } ,
2026-01-17 06:35:49 +00:00
} ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , model , { } )
2026-01-31 01:53:22 +00:00
expect ( result [ 0 ] . providerOptions ? . copilot ) . toEqual ( { someOption : "value" } )
2026-01-17 06:35:49 +00:00
expect ( result [ 0 ] . providerOptions ? . [ "github-copilot" ] ) . toBeUndefined ( )
} )
test ( "bedrock remaps providerID to 'bedrock' key" , ( ) = > {
const model = createModel ( "my-bedrock" , "@ai-sdk/amazon-bedrock" )
const msgs = [
{
role : "user" ,
content : "Hello" ,
providerOptions : {
"my-bedrock" : { someOption : "value" } ,
} ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , model , { } )
expect ( result [ 0 ] . providerOptions ? . bedrock ) . toEqual ( { someOption : "value" } )
expect ( result [ 0 ] . providerOptions ? . [ "my-bedrock" ] ) . toBeUndefined ( )
} )
} )
2026-01-21 16:42:13 +00:00
describe ( "ProviderTransform.message - claude w/bedrock custom inference profile" , ( ) = > {
test ( "adds cachePoint" , ( ) = > {
const model = {
id : "amazon-bedrock/custom-claude-sonnet-4.5" ,
providerID : "amazon-bedrock" ,
api : {
id : "arn:aws:bedrock:xxx:yyy:application-inference-profile/zzz" ,
url : "https://api.test.com" ,
npm : "@ai-sdk/amazon-bedrock" ,
} ,
name : "Custom inference profile" ,
capabilities : { } ,
options : { } ,
headers : { } ,
} as any
const msgs = [
{
role : "user" ,
content : "Hello" ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , model , { } )
expect ( result [ 0 ] . providerOptions ? . bedrock ) . toEqual (
expect . objectContaining ( {
cachePoint : {
2026-02-01 20:42:42 +00:00
type : "default" ,
2026-01-21 16:42:13 +00:00
} ,
} ) ,
)
} )
} )
2026-03-24 18:42:20 +00:00
describe ( "ProviderTransform.message - bedrock caching with non-bedrock providerID" , ( ) = > {
test ( "applies cache options at message level when npm package is amazon-bedrock" , ( ) = > {
const model = {
id : "aws/us.anthropic.claude-opus-4-6-v1" ,
providerID : "aws" ,
api : {
id : "us.anthropic.claude-opus-4-6-v1" ,
url : "https://bedrock-runtime.us-east-1.amazonaws.com" ,
npm : "@ai-sdk/amazon-bedrock" ,
} ,
name : "Claude Opus 4.6" ,
capabilities : { } ,
options : { } ,
headers : { } ,
} as any
const msgs = [
{
role : "system" ,
content : [ { type : "text" , text : "You are a helpful assistant" } ] ,
} ,
{
role : "user" ,
content : [ { type : "text" , text : "Hello" } ] ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , model , { } ) as any [ ]
2026-03-24 18:43:20 +00:00
2026-03-24 18:42:20 +00:00
// Cache should be at the message level and not the content-part level
expect ( result [ 0 ] . providerOptions ? . bedrock ) . toEqual ( {
cachePoint : { type : "default" } ,
} )
expect ( result [ 0 ] . content [ 0 ] . providerOptions ? . bedrock ) . toBeUndefined ( )
} )
} )
2026-02-14 18:32:29 +00:00
describe ( "ProviderTransform.message - cache control on gateway" , ( ) = > {
const createModel = ( overrides : Partial < any > = { } ) = >
( {
id : "anthropic/claude-sonnet-4" ,
providerID : "vercel" ,
api : {
id : "anthropic/claude-sonnet-4" ,
url : "https://ai-gateway.vercel.sh/v3/ai" ,
npm : "@ai-sdk/gateway" ,
} ,
name : "Claude Sonnet 4" ,
capabilities : {
temperature : true ,
reasoning : true ,
attachment : true ,
toolcall : true ,
input : { text : true , audio : false , image : true , video : false , pdf : true } ,
output : { text : true , audio : false , image : false , video : false , pdf : false } ,
interleaved : false ,
} ,
cost : { input : 0.001 , output : 0.002 , cache : { read : 0.0001 , write : 0.0002 } } ,
limit : { context : 200_000 , output : 8192 } ,
status : "active" ,
options : { } ,
headers : { } ,
. . . overrides ,
} ) as any
test ( "gateway does not set cache control for anthropic models" , ( ) = > {
const model = createModel ( )
const msgs = [
{
role : "system" ,
content : [ { type : "text" , text : "You are a helpful assistant" } ] ,
} ,
{
role : "user" ,
content : "Hello" ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , model , { } ) as any [ ]
expect ( result [ 0 ] . content [ 0 ] . providerOptions ) . toBeUndefined ( )
expect ( result [ 0 ] . providerOptions ) . toBeUndefined ( )
} )
test ( "non-gateway anthropic keeps existing cache control behavior" , ( ) = > {
const model = createModel ( {
providerID : "anthropic" ,
api : {
id : "claude-sonnet-4" ,
url : "https://api.anthropic.com" ,
npm : "@ai-sdk/anthropic" ,
} ,
} )
const msgs = [
{
role : "system" ,
content : "You are a helpful assistant" ,
} ,
{
role : "user" ,
content : "Hello" ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , model , { } ) as any [ ]
2026-03-31 20:16:14 +00:00
expect ( result [ 0 ] . providerOptions ) . toEqual ( {
anthropic : {
cacheControl : {
type : "ephemeral" ,
} ,
} ,
openrouter : {
cacheControl : {
type : "ephemeral" ,
} ,
} ,
bedrock : {
cachePoint : {
type : "default" ,
} ,
} ,
openaiCompatible : {
cache_control : {
type : "ephemeral" ,
} ,
} ,
copilot : {
copilot_cache_control : {
type : "ephemeral" ,
} ,
} ,
2026-04-13 13:17:13 +00:00
alibaba : {
cacheControl : {
type : "ephemeral" ,
} ,
} ,
2026-03-31 20:16:14 +00:00
} )
} )
test ( "google-vertex-anthropic applies cache control" , ( ) = > {
const model = createModel ( {
providerID : "google-vertex-anthropic" ,
api : {
id : "google-vertex-anthropic" ,
url : "https://us-central1-aiplatform.googleapis.com" ,
npm : "@ai-sdk/google-vertex/anthropic" ,
} ,
id : "claude-sonnet-4@20250514" ,
} )
const msgs = [
{
role : "system" ,
content : "You are a helpful assistant" ,
} ,
{
role : "user" ,
content : "Hello" ,
} ,
] as any [ ]
const result = ProviderTransform . message ( msgs , model , { } ) as any [ ]
2026-02-14 18:32:29 +00:00
expect ( result [ 0 ] . providerOptions ) . toEqual ( {
anthropic : {
cacheControl : {
type : "ephemeral" ,
} ,
} ,
openrouter : {
cacheControl : {
type : "ephemeral" ,
} ,
} ,
bedrock : {
cachePoint : {
type : "default" ,
} ,
} ,
openaiCompatible : {
cache_control : {
type : "ephemeral" ,
} ,
} ,
copilot : {
copilot_cache_control : {
type : "ephemeral" ,
} ,
} ,
2026-04-13 13:17:13 +00:00
alibaba : {
cacheControl : {
type : "ephemeral" ,
} ,
} ,
2026-02-14 18:32:29 +00:00
} )
} )
} )
2025-12-30 22:37:32 +00:00
describe ( "ProviderTransform.variants" , ( ) = > {
const createMockModel = ( overrides : Partial < any > = { } ) : any = > ( {
id : "test/test-model" ,
providerID : "test" ,
api : {
id : "test-model" ,
url : "https://api.test.com" ,
npm : "@ai-sdk/openai" ,
} ,
name : "Test Model" ,
capabilities : {
temperature : true ,
reasoning : true ,
attachment : true ,
toolcall : true ,
input : { text : true , audio : false , image : true , video : false , pdf : false } ,
output : { text : true , audio : false , image : false , video : false , pdf : false } ,
interleaved : false ,
} ,
cost : {
input : 0.001 ,
output : 0.002 ,
cache : { read : 0.0001 , write : 0.0002 } ,
} ,
limit : {
2026-01-29 04:02:07 +00:00
context : 200_000 ,
output : 64_000 ,
2025-12-30 22:37:32 +00:00
} ,
status : "active" ,
options : { } ,
headers : { } ,
release_date : "2024-01-01" ,
. . . overrides ,
} )
test ( "returns empty object when model has no reasoning capabilities" , ( ) = > {
const model = createMockModel ( {
capabilities : { reasoning : false } ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( { } )
} )
test ( "deepseek returns empty object" , ( ) = > {
const model = createMockModel ( {
id : "deepseek/deepseek-chat" ,
providerID : "deepseek" ,
api : {
id : "deepseek-chat" ,
url : "https://api.deepseek.com" ,
npm : "@ai-sdk/openai-compatible" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( { } )
} )
test ( "minimax returns empty object" , ( ) = > {
const model = createMockModel ( {
id : "minimax/minimax-model" ,
providerID : "minimax" ,
api : {
id : "minimax-model" ,
url : "https://api.minimax.com" ,
npm : "@ai-sdk/openai-compatible" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( { } )
} )
test ( "glm returns empty object" , ( ) = > {
const model = createMockModel ( {
id : "glm/glm-4" ,
providerID : "glm" ,
api : {
id : "glm-4" ,
url : "https://api.glm.com" ,
npm : "@ai-sdk/openai-compatible" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( { } )
} )
2026-04-29 21:26:24 +00:00
test ( "mistral models with reasoning support return variants" , ( ) = > {
2026-04-21 20:45:06 +00:00
const model = createMockModel ( {
id : "mistral/mistral-small-latest" ,
providerID : "mistral" ,
api : {
id : "mistral-small-latest" ,
url : "https://api.mistral.com" ,
npm : "@ai-sdk/mistral" ,
} ,
capabilities : { reasoning : true } ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( {
high : { reasoningEffort : "high" } ,
} )
} )
2026-04-29 21:26:24 +00:00
test ( "mistral-medium-3.5 with reasoning returns variants" , ( ) = > {
const model = createMockModel ( {
id : "mistral/mistral-medium-3.5" ,
providerID : "mistral" ,
api : {
id : "mistral-medium-3.5" ,
url : "https://api.mistral.com" ,
npm : "@ai-sdk/mistral" ,
} ,
capabilities : { reasoning : true } ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( {
high : { reasoningEffort : "high" } ,
} )
} )
2026-04-21 20:45:06 +00:00
test ( "mistral without reasoning returns empty object" , ( ) = > {
const model = createMockModel ( {
id : "mistral/mistral-large" ,
providerID : "mistral" ,
api : {
id : "mistral-large-latest" ,
url : "https://api.mistral.com" ,
npm : "@ai-sdk/mistral" ,
} ,
capabilities : { reasoning : false } ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( { } )
} )
test ( "mistral large with reasoning returns empty object (only small supports reasoning)" , ( ) = > {
2025-12-30 22:37:32 +00:00
const model = createMockModel ( {
id : "mistral/mistral-large" ,
providerID : "mistral" ,
api : {
id : "mistral-large-latest" ,
url : "https://api.mistral.com" ,
npm : "@ai-sdk/mistral" ,
} ,
2026-04-21 20:45:06 +00:00
capabilities : { reasoning : true } ,
2025-12-30 22:37:32 +00:00
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( { } )
} )
describe ( "@openrouter/ai-sdk-provider" , ( ) = > {
test ( "returns empty object for non-qualifying models" , ( ) = > {
const model = createMockModel ( {
id : "openrouter/test-model" ,
providerID : "openrouter" ,
api : {
id : "test-model" ,
url : "https://openrouter.ai" ,
npm : "@openrouter/ai-sdk-provider" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( { } )
} )
test ( "gpt models return OPENAI_EFFORTS with reasoning" , ( ) = > {
const model = createMockModel ( {
id : "openrouter/gpt-4" ,
providerID : "openrouter" ,
api : {
id : "gpt-4" ,
url : "https://openrouter.ai" ,
npm : "@openrouter/ai-sdk-provider" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "none" , "minimal" , "low" , "medium" , "high" , "xhigh" ] )
expect ( result . low ) . toEqual ( { reasoning : { effort : "low" } } )
expect ( result . high ) . toEqual ( { reasoning : { effort : "high" } } )
} )
test ( "gemini-3 returns OPENAI_EFFORTS with reasoning" , ( ) = > {
const model = createMockModel ( {
id : "openrouter/gemini-3-5-pro" ,
providerID : "openrouter" ,
api : {
id : "gemini-3-5-pro" ,
url : "https://openrouter.ai" ,
npm : "@openrouter/ai-sdk-provider" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "none" , "minimal" , "low" , "medium" , "high" , "xhigh" ] )
} )
2026-01-18 20:44:39 +00:00
test ( "grok-4 returns empty object" , ( ) = > {
2025-12-30 22:37:32 +00:00
const model = createMockModel ( {
id : "openrouter/grok-4" ,
providerID : "openrouter" ,
api : {
id : "grok-4" ,
url : "https://openrouter.ai" ,
npm : "@openrouter/ai-sdk-provider" ,
} ,
} )
const result = ProviderTransform . variants ( model )
2026-01-18 20:44:39 +00:00
expect ( result ) . toEqual ( { } )
} )
test ( "grok-3-mini returns low and high with reasoning" , ( ) = > {
const model = createMockModel ( {
id : "openrouter/grok-3-mini" ,
providerID : "openrouter" ,
api : {
id : "grok-3-mini" ,
url : "https://openrouter.ai" ,
npm : "@openrouter/ai-sdk-provider" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "high" ] )
expect ( result . low ) . toEqual ( { reasoning : { effort : "low" } } )
expect ( result . high ) . toEqual ( { reasoning : { effort : "high" } } )
2025-12-30 22:37:32 +00:00
} )
} )
describe ( "@ai-sdk/gateway" , ( ) = > {
2026-02-19 22:17:57 +00:00
test ( "anthropic sonnet 4.6 models return adaptive thinking options" , ( ) = > {
const model = createMockModel ( {
id : "anthropic/claude-sonnet-4-6" ,
providerID : "gateway" ,
api : {
id : "anthropic/claude-sonnet-4-6" ,
url : "https://gateway.ai" ,
npm : "@ai-sdk/gateway" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "max" ] )
expect ( result . medium ) . toEqual ( {
thinking : {
type : "adaptive" ,
} ,
effort : "medium" ,
} )
} )
test ( "anthropic sonnet 4.6 dot-format models return adaptive thinking options" , ( ) = > {
const model = createMockModel ( {
id : "anthropic/claude-sonnet-4-6" ,
providerID : "gateway" ,
api : {
id : "anthropic/claude-sonnet-4.6" ,
url : "https://gateway.ai" ,
npm : "@ai-sdk/gateway" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "max" ] )
expect ( result . medium ) . toEqual ( {
thinking : {
type : "adaptive" ,
} ,
effort : "medium" ,
} )
} )
test ( "anthropic opus 4.6 dot-format models return adaptive thinking options" , ( ) = > {
const model = createMockModel ( {
id : "anthropic/claude-opus-4-6" ,
providerID : "gateway" ,
api : {
id : "anthropic/claude-opus-4.6" ,
url : "https://gateway.ai" ,
npm : "@ai-sdk/gateway" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "max" ] )
expect ( result . high ) . toEqual ( {
thinking : {
type : "adaptive" ,
} ,
effort : "high" ,
} )
} )
2026-04-16 15:57:36 +00:00
test ( "anthropic opus 4.7 models return adaptive thinking options with xhigh" , ( ) = > {
const model = createMockModel ( {
id : "anthropic/claude-opus-4-7" ,
providerID : "gateway" ,
api : {
id : "anthropic/claude-opus-4-7" ,
url : "https://gateway.ai" ,
npm : "@ai-sdk/gateway" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "xhigh" , "max" ] )
expect ( result . xhigh ) . toEqual ( {
thinking : {
type : "adaptive" ,
} ,
effort : "xhigh" ,
} )
expect ( result . max ) . toEqual ( {
thinking : {
type : "adaptive" ,
} ,
effort : "max" ,
} )
} )
test ( "anthropic opus 4.7 dot-format models return adaptive thinking options with xhigh" , ( ) = > {
const model = createMockModel ( {
id : "anthropic/claude-opus-4-7" ,
providerID : "gateway" ,
api : {
id : "anthropic/claude-opus-4.7" ,
url : "https://gateway.ai" ,
npm : "@ai-sdk/gateway" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "xhigh" , "max" ] )
} )
2026-02-14 18:32:29 +00:00
test ( "anthropic models return anthropic thinking options" , ( ) = > {
const model = createMockModel ( {
id : "anthropic/claude-sonnet-4" ,
providerID : "gateway" ,
api : {
id : "anthropic/claude-sonnet-4" ,
url : "https://gateway.ai" ,
npm : "@ai-sdk/gateway" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "high" , "max" ] )
expect ( result . high ) . toEqual ( {
thinking : {
type : "enabled" ,
budgetTokens : 16000 ,
} ,
} )
expect ( result . max ) . toEqual ( {
thinking : {
type : "enabled" ,
budgetTokens : 31999 ,
} ,
} )
} )
2025-12-30 22:37:32 +00:00
test ( "returns OPENAI_EFFORTS with reasoningEffort" , ( ) = > {
const model = createMockModel ( {
id : "gateway/gateway-model" ,
providerID : "gateway" ,
api : {
id : "gateway-model" ,
url : "https://gateway.ai" ,
npm : "@ai-sdk/gateway" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "none" , "minimal" , "low" , "medium" , "high" , "xhigh" ] )
expect ( result . low ) . toEqual ( { reasoningEffort : "low" } )
expect ( result . high ) . toEqual ( { reasoningEffort : "high" } )
} )
} )
2026-01-24 05:09:47 +00:00
describe ( "@ai-sdk/github-copilot" , ( ) = > {
test ( "standard models return low, medium, high" , ( ) = > {
const model = createMockModel ( {
id : "gpt-4.5" ,
providerID : "github-copilot" ,
api : {
id : "gpt-4.5" ,
url : "https://api.githubcopilot.com" ,
npm : "@ai-sdk/github-copilot" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" ] )
expect ( result . low ) . toEqual ( {
reasoningEffort : "low" ,
reasoningSummary : "auto" ,
include : [ "reasoning.encrypted_content" ] ,
} )
} )
test ( "gpt-5.1-codex-max includes xhigh" , ( ) = > {
const model = createMockModel ( {
id : "gpt-5.1-codex-max" ,
providerID : "github-copilot" ,
api : {
id : "gpt-5.1-codex-max" ,
url : "https://api.githubcopilot.com" ,
npm : "@ai-sdk/github-copilot" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "xhigh" ] )
} )
test ( "gpt-5.1-codex-mini does not include xhigh" , ( ) = > {
const model = createMockModel ( {
id : "gpt-5.1-codex-mini" ,
providerID : "github-copilot" ,
api : {
id : "gpt-5.1-codex-mini" ,
url : "https://api.githubcopilot.com" ,
npm : "@ai-sdk/github-copilot" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" ] )
} )
test ( "gpt-5.1-codex does not include xhigh" , ( ) = > {
const model = createMockModel ( {
id : "gpt-5.1-codex" ,
providerID : "github-copilot" ,
api : {
id : "gpt-5.1-codex" ,
url : "https://api.githubcopilot.com" ,
npm : "@ai-sdk/github-copilot" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" ] )
} )
test ( "gpt-5.2 includes xhigh" , ( ) = > {
const model = createMockModel ( {
id : "gpt-5.2" ,
providerID : "github-copilot" ,
api : {
id : "gpt-5.2" ,
url : "https://api.githubcopilot.com" ,
npm : "@ai-sdk/github-copilot" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "xhigh" ] )
expect ( result . xhigh ) . toEqual ( {
reasoningEffort : "xhigh" ,
reasoningSummary : "auto" ,
include : [ "reasoning.encrypted_content" ] ,
} )
} )
test ( "gpt-5.2-codex includes xhigh" , ( ) = > {
const model = createMockModel ( {
id : "gpt-5.2-codex" ,
providerID : "github-copilot" ,
api : {
id : "gpt-5.2-codex" ,
url : "https://api.githubcopilot.com" ,
npm : "@ai-sdk/github-copilot" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "xhigh" ] )
} )
2026-03-09 14:07:12 +00:00
test ( "gpt-5.3-codex includes xhigh" , ( ) = > {
const model = createMockModel ( {
id : "gpt-5.3-codex" ,
providerID : "github-copilot" ,
api : {
id : "gpt-5.3-codex" ,
url : "https://api.githubcopilot.com" ,
npm : "@ai-sdk/github-copilot" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "xhigh" ] )
} )
test ( "gpt-5.4 includes xhigh" , ( ) = > {
const model = createMockModel ( {
id : "gpt-5.4" ,
release_date : "2026-03-05" ,
providerID : "github-copilot" ,
api : {
id : "gpt-5.4" ,
url : "https://api.githubcopilot.com" ,
npm : "@ai-sdk/github-copilot" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "xhigh" ] )
} )
2026-01-24 05:09:47 +00:00
} )
2025-12-30 22:37:32 +00:00
describe ( "@ai-sdk/cerebras" , ( ) = > {
test ( "returns WIDELY_SUPPORTED_EFFORTS with reasoningEffort" , ( ) = > {
const model = createMockModel ( {
id : "cerebras/llama-4" ,
providerID : "cerebras" ,
api : {
id : "llama-4-sc" ,
url : "https://api.cerebras.ai" ,
npm : "@ai-sdk/cerebras" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" ] )
expect ( result . low ) . toEqual ( { reasoningEffort : "low" } )
expect ( result . high ) . toEqual ( { reasoningEffort : "high" } )
} )
} )
describe ( "@ai-sdk/togetherai" , ( ) = > {
test ( "returns WIDELY_SUPPORTED_EFFORTS with reasoningEffort" , ( ) = > {
const model = createMockModel ( {
id : "togetherai/llama-4" ,
providerID : "togetherai" ,
api : {
id : "llama-4-sc" ,
url : "https://api.togetherai.com" ,
npm : "@ai-sdk/togetherai" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" ] )
expect ( result . low ) . toEqual ( { reasoningEffort : "low" } )
expect ( result . high ) . toEqual ( { reasoningEffort : "high" } )
} )
} )
describe ( "@ai-sdk/xai" , ( ) = > {
2026-01-18 20:44:39 +00:00
test ( "grok-3 returns empty object" , ( ) = > {
2025-12-30 22:37:32 +00:00
const model = createMockModel ( {
id : "xai/grok-3" ,
providerID : "xai" ,
api : {
id : "grok-3" ,
url : "https://api.x.ai" ,
npm : "@ai-sdk/xai" ,
} ,
} )
const result = ProviderTransform . variants ( model )
2026-01-18 20:44:39 +00:00
expect ( result ) . toEqual ( { } )
} )
test ( "grok-3-mini returns low and high with reasoningEffort" , ( ) = > {
const model = createMockModel ( {
id : "xai/grok-3-mini" ,
providerID : "xai" ,
api : {
id : "grok-3-mini" ,
url : "https://api.x.ai" ,
npm : "@ai-sdk/xai" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "high" ] )
2025-12-30 22:37:32 +00:00
expect ( result . low ) . toEqual ( { reasoningEffort : "low" } )
expect ( result . high ) . toEqual ( { reasoningEffort : "high" } )
} )
} )
describe ( "@ai-sdk/deepinfra" , ( ) = > {
test ( "returns WIDELY_SUPPORTED_EFFORTS with reasoningEffort" , ( ) = > {
const model = createMockModel ( {
id : "deepinfra/llama-4" ,
providerID : "deepinfra" ,
api : {
id : "llama-4-sc" ,
url : "https://api.deepinfra.com" ,
npm : "@ai-sdk/deepinfra" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" ] )
expect ( result . low ) . toEqual ( { reasoningEffort : "low" } )
expect ( result . high ) . toEqual ( { reasoningEffort : "high" } )
} )
} )
describe ( "@ai-sdk/openai-compatible" , ( ) = > {
test ( "returns WIDELY_SUPPORTED_EFFORTS with reasoningEffort" , ( ) = > {
const model = createMockModel ( {
id : "custom-provider/custom-model" ,
providerID : "custom-provider" ,
api : {
id : "custom-model" ,
url : "https://api.custom.com" ,
npm : "@ai-sdk/openai-compatible" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" ] )
expect ( result . low ) . toEqual ( { reasoningEffort : "low" } )
expect ( result . high ) . toEqual ( { reasoningEffort : "high" } )
} )
} )
describe ( "@ai-sdk/azure" , ( ) = > {
test ( "o1-mini returns empty object" , ( ) = > {
const model = createMockModel ( {
id : "o1-mini" ,
providerID : "azure" ,
api : {
id : "o1-mini" ,
url : "https://azure.com" ,
npm : "@ai-sdk/azure" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( { } )
} )
test ( "standard azure models return custom efforts with reasoningSummary" , ( ) = > {
const model = createMockModel ( {
2026-01-02 18:38:44 +00:00
id : "o1" ,
2025-12-30 22:37:32 +00:00
providerID : "azure" ,
api : {
2026-01-02 18:38:44 +00:00
id : "o1" ,
2025-12-30 22:37:32 +00:00
url : "https://azure.com" ,
npm : "@ai-sdk/azure" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" ] )
expect ( result . low ) . toEqual ( {
reasoningEffort : "low" ,
reasoningSummary : "auto" ,
include : [ "reasoning.encrypted_content" ] ,
} )
} )
test ( "gpt-5 adds minimal effort" , ( ) = > {
const model = createMockModel ( {
2026-01-02 18:38:44 +00:00
id : "gpt-5" ,
2025-12-30 22:37:32 +00:00
providerID : "azure" ,
api : {
id : "gpt-5" ,
url : "https://azure.com" ,
npm : "@ai-sdk/azure" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "minimal" , "low" , "medium" , "high" ] )
} )
} )
describe ( "@ai-sdk/openai" , ( ) = > {
test ( "gpt-5-pro returns empty object" , ( ) = > {
const model = createMockModel ( {
id : "gpt-5-pro" ,
providerID : "openai" ,
api : {
id : "gpt-5-pro" ,
url : "https://api.openai.com" ,
npm : "@ai-sdk/openai" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( { } )
} )
test ( "standard openai models return custom efforts with reasoningSummary" , ( ) = > {
const model = createMockModel ( {
2026-01-02 18:38:44 +00:00
id : "gpt-5" ,
2025-12-30 22:37:32 +00:00
providerID : "openai" ,
api : {
2026-01-02 18:38:44 +00:00
id : "gpt-5" ,
2025-12-30 22:37:32 +00:00
url : "https://api.openai.com" ,
npm : "@ai-sdk/openai" ,
} ,
release_date : "2024-06-01" ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "minimal" , "low" , "medium" , "high" ] )
expect ( result . low ) . toEqual ( {
reasoningEffort : "low" ,
reasoningSummary : "auto" ,
include : [ "reasoning.encrypted_content" ] ,
} )
} )
test ( "models after 2025-11-13 include 'none' effort" , ( ) = > {
const model = createMockModel ( {
2026-01-02 18:38:44 +00:00
id : "gpt-5-nano" ,
2025-12-30 22:37:32 +00:00
providerID : "openai" ,
api : {
2026-01-02 18:38:44 +00:00
id : "gpt-5-nano" ,
2025-12-30 22:37:32 +00:00
url : "https://api.openai.com" ,
npm : "@ai-sdk/openai" ,
} ,
release_date : "2025-11-14" ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "none" , "minimal" , "low" , "medium" , "high" ] )
} )
test ( "models after 2025-12-04 include 'xhigh' effort" , ( ) = > {
const model = createMockModel ( {
id : "openai/gpt-5-chat" ,
providerID : "openai" ,
api : {
id : "gpt-5-chat" ,
url : "https://api.openai.com" ,
npm : "@ai-sdk/openai" ,
} ,
release_date : "2025-12-05" ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "none" , "minimal" , "low" , "medium" , "high" , "xhigh" ] )
} )
} )
describe ( "@ai-sdk/anthropic" , ( ) = > {
2026-02-19 22:17:57 +00:00
test ( "sonnet 4.6 returns adaptive thinking options" , ( ) = > {
const model = createMockModel ( {
id : "anthropic/claude-sonnet-4-6" ,
providerID : "anthropic" ,
api : {
id : "claude-sonnet-4-6" ,
url : "https://api.anthropic.com" ,
npm : "@ai-sdk/anthropic" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "max" ] )
expect ( result . high ) . toEqual ( {
thinking : {
type : "adaptive" ,
} ,
effort : "high" ,
} )
} )
2026-04-16 15:57:36 +00:00
test ( "opus 4.7 returns adaptive thinking options with xhigh" , ( ) = > {
const model = createMockModel ( {
id : "anthropic/claude-opus-4-7" ,
providerID : "anthropic" ,
api : {
id : "claude-opus-4-7" ,
url : "https://api.anthropic.com" ,
npm : "@ai-sdk/anthropic" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "xhigh" , "max" ] )
expect ( result . xhigh ) . toEqual ( {
thinking : {
type : "adaptive" ,
2026-04-16 19:12:43 +00:00
display : "summarized" ,
2026-04-16 15:57:36 +00:00
} ,
effort : "xhigh" ,
} )
expect ( result . max ) . toEqual ( {
thinking : {
type : "adaptive" ,
2026-04-16 19:12:43 +00:00
display : "summarized" ,
2026-04-16 15:57:36 +00:00
} ,
effort : "max" ,
} )
} )
2026-04-28 19:58:51 +00:00
test ( "github copilot opus 4.7 returns only medium reasoning effort" , ( ) = > {
const model = createMockModel ( {
id : "claude-opus-4.7" ,
providerID : "github-copilot" ,
api : {
id : "claude-opus-4.7" ,
url : "https://api.githubcopilot.com/v1" ,
npm : "@ai-sdk/anthropic" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( {
medium : {
thinking : {
type : "adaptive" ,
display : "summarized" ,
} ,
effort : "medium" ,
} ,
} )
} )
2025-12-30 22:37:32 +00:00
test ( "returns high and max with thinking config" , ( ) = > {
const model = createMockModel ( {
id : "anthropic/claude-4" ,
providerID : "anthropic" ,
api : {
id : "claude-4" ,
url : "https://api.anthropic.com" ,
npm : "@ai-sdk/anthropic" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "high" , "max" ] )
expect ( result . high ) . toEqual ( {
thinking : {
type : "enabled" ,
budgetTokens : 16000 ,
} ,
} )
expect ( result . max ) . toEqual ( {
thinking : {
type : "enabled" ,
budgetTokens : 31999 ,
} ,
} )
} )
} )
describe ( "@ai-sdk/amazon-bedrock" , ( ) = > {
2026-02-19 22:17:57 +00:00
test ( "anthropic sonnet 4.6 returns adaptive reasoning options" , ( ) = > {
const model = createMockModel ( {
id : "bedrock/anthropic-claude-sonnet-4-6" ,
providerID : "bedrock" ,
api : {
id : "anthropic.claude-sonnet-4-6" ,
url : "https://bedrock.amazonaws.com" ,
npm : "@ai-sdk/amazon-bedrock" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "max" ] )
expect ( result . max ) . toEqual ( {
reasoningConfig : {
2026-04-16 15:57:36 +00:00
type : "adaptive" ,
maxReasoningEffort : "max" ,
} ,
} )
} )
test ( "anthropic opus 4.7 returns adaptive reasoning options with xhigh" , ( ) = > {
const model = createMockModel ( {
id : "bedrock/anthropic-claude-opus-4-7" ,
providerID : "bedrock" ,
api : {
id : "anthropic.claude-opus-4-7" ,
url : "https://bedrock.amazonaws.com" ,
npm : "@ai-sdk/amazon-bedrock" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "xhigh" , "max" ] )
expect ( result . xhigh ) . toEqual ( {
reasoningConfig : {
type : "adaptive" ,
maxReasoningEffort : "xhigh" ,
2026-04-18 22:46:15 +00:00
display : "summarized" ,
2026-04-16 15:57:36 +00:00
} ,
} )
expect ( result . max ) . toEqual ( {
reasoningConfig : {
2026-02-19 22:17:57 +00:00
type : "adaptive" ,
maxReasoningEffort : "max" ,
2026-04-18 22:46:15 +00:00
display : "summarized" ,
2026-02-19 22:17:57 +00:00
} ,
} )
} )
2025-12-30 22:37:32 +00:00
test ( "returns WIDELY_SUPPORTED_EFFORTS with reasoningConfig" , ( ) = > {
const model = createMockModel ( {
id : "bedrock/llama-4" ,
providerID : "bedrock" ,
api : {
id : "llama-4-sc" ,
url : "https://bedrock.amazonaws.com" ,
npm : "@ai-sdk/amazon-bedrock" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" ] )
expect ( result . low ) . toEqual ( {
reasoningConfig : {
type : "enabled" ,
maxReasoningEffort : "low" ,
} ,
} )
} )
} )
describe ( "@ai-sdk/google" , ( ) = > {
test ( "gemini-2.5 returns high and max with thinkingConfig and thinkingBudget" , ( ) = > {
const model = createMockModel ( {
id : "google/gemini-2.5-pro" ,
providerID : "google" ,
api : {
id : "gemini-2.5-pro" ,
url : "https://generativelanguage.googleapis.com" ,
npm : "@ai-sdk/google" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "high" , "max" ] )
expect ( result . high ) . toEqual ( {
thinkingConfig : {
includeThoughts : true ,
thinkingBudget : 16000 ,
} ,
} )
expect ( result . max ) . toEqual ( {
thinkingConfig : {
includeThoughts : true ,
thinkingBudget : 24576 ,
} ,
} )
} )
test ( "other gemini models return low and high with thinkingLevel" , ( ) = > {
const model = createMockModel ( {
id : "google/gemini-2.0-pro" ,
providerID : "google" ,
api : {
id : "gemini-2.0-pro" ,
url : "https://generativelanguage.googleapis.com" ,
npm : "@ai-sdk/google" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "high" ] )
expect ( result . low ) . toEqual ( {
2026-02-19 18:35:51 +00:00
thinkingConfig : {
includeThoughts : true ,
thinkingLevel : "low" ,
} ,
2025-12-30 22:37:32 +00:00
} )
expect ( result . high ) . toEqual ( {
2026-02-19 18:35:51 +00:00
thinkingConfig : {
includeThoughts : true ,
thinkingLevel : "high" ,
} ,
2025-12-30 22:37:32 +00:00
} )
} )
} )
describe ( "@ai-sdk/google-vertex" , ( ) = > {
test ( "gemini-2.5 returns high and max with thinkingConfig and thinkingBudget" , ( ) = > {
const model = createMockModel ( {
id : "google-vertex/gemini-2.5-pro" ,
providerID : "google-vertex" ,
api : {
id : "gemini-2.5-pro" ,
url : "https://vertexai.googleapis.com" ,
npm : "@ai-sdk/google-vertex" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "high" , "max" ] )
} )
test ( "other vertex models return low and high with thinkingLevel" , ( ) = > {
const model = createMockModel ( {
id : "google-vertex/gemini-2.0-pro" ,
providerID : "google-vertex" ,
api : {
id : "gemini-2.0-pro" ,
url : "https://vertexai.googleapis.com" ,
npm : "@ai-sdk/google-vertex" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "high" ] )
} )
} )
describe ( "@ai-sdk/cohere" , ( ) = > {
test ( "returns empty object" , ( ) = > {
const model = createMockModel ( {
id : "cohere/command-r" ,
providerID : "cohere" ,
api : {
id : "command-r" ,
url : "https://api.cohere.com" ,
npm : "@ai-sdk/cohere" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( { } )
} )
} )
describe ( "@ai-sdk/groq" , ( ) = > {
test ( "returns none and WIDELY_SUPPORTED_EFFORTS with thinkingLevel" , ( ) = > {
const model = createMockModel ( {
id : "groq/llama-4" ,
providerID : "groq" ,
api : {
id : "llama-4-sc" ,
url : "https://api.groq.com" ,
npm : "@ai-sdk/groq" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "none" , "low" , "medium" , "high" ] )
expect ( result . none ) . toEqual ( {
2026-02-19 18:35:51 +00:00
reasoningEffort : "none" ,
2025-12-30 22:37:32 +00:00
} )
expect ( result . low ) . toEqual ( {
2026-02-19 18:35:51 +00:00
reasoningEffort : "low" ,
2025-12-30 22:37:32 +00:00
} )
} )
} )
describe ( "@ai-sdk/perplexity" , ( ) = > {
test ( "returns empty object" , ( ) = > {
const model = createMockModel ( {
id : "perplexity/sonar-plus" ,
providerID : "perplexity" ,
api : {
id : "sonar-plus" ,
url : "https://api.perplexity.ai" ,
npm : "@ai-sdk/perplexity" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( { } )
} )
} )
2026-03-10 15:05:45 +00:00
describe ( "@jerome-benoit/sap-ai-provider-v2" , ( ) = > {
test ( "anthropic models return thinking variants" , ( ) = > {
const model = createMockModel ( {
id : "sap-ai-core/anthropic--claude-sonnet-4" ,
providerID : "sap-ai-core" ,
api : {
id : "anthropic--claude-sonnet-4" ,
url : "https://api.ai.sap" ,
npm : "@jerome-benoit/sap-ai-provider-v2" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "high" , "max" ] )
expect ( result . high ) . toEqual ( {
thinking : {
type : "enabled" ,
budgetTokens : 16000 ,
} ,
} )
expect ( result . max ) . toEqual ( {
thinking : {
type : "enabled" ,
budgetTokens : 31999 ,
} ,
} )
} )
test ( "anthropic 4.6 models return adaptive thinking variants" , ( ) = > {
const model = createMockModel ( {
id : "sap-ai-core/anthropic--claude-sonnet-4-6" ,
providerID : "sap-ai-core" ,
api : {
id : "anthropic--claude-sonnet-4-6" ,
url : "https://api.ai.sap" ,
npm : "@jerome-benoit/sap-ai-provider-v2" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" , "max" ] )
expect ( result . low ) . toEqual ( {
thinking : {
type : "adaptive" ,
} ,
effort : "low" ,
} )
expect ( result . max ) . toEqual ( {
thinking : {
type : "adaptive" ,
} ,
effort : "max" ,
} )
} )
test ( "gemini 2.5 models return thinkingConfig variants" , ( ) = > {
const model = createMockModel ( {
id : "sap-ai-core/gcp--gemini-2.5-pro" ,
providerID : "sap-ai-core" ,
api : {
id : "gcp--gemini-2.5-pro" ,
url : "https://api.ai.sap" ,
npm : "@jerome-benoit/sap-ai-provider-v2" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "high" , "max" ] )
expect ( result . high ) . toEqual ( {
thinkingConfig : {
includeThoughts : true ,
thinkingBudget : 16000 ,
} ,
} )
expect ( result . max ) . toEqual ( {
thinkingConfig : {
includeThoughts : true ,
thinkingBudget : 24576 ,
} ,
} )
} )
test ( "gpt models return reasoningEffort variants" , ( ) = > {
const model = createMockModel ( {
id : "sap-ai-core/azure-openai--gpt-4o" ,
providerID : "sap-ai-core" ,
api : {
id : "azure-openai--gpt-4o" ,
url : "https://api.ai.sap" ,
npm : "@jerome-benoit/sap-ai-provider-v2" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" ] )
expect ( result . low ) . toEqual ( { reasoningEffort : "low" } )
expect ( result . high ) . toEqual ( { reasoningEffort : "high" } )
} )
test ( "o-series models return reasoningEffort variants" , ( ) = > {
const model = createMockModel ( {
id : "sap-ai-core/azure-openai--o3-mini" ,
providerID : "sap-ai-core" ,
api : {
id : "azure-openai--o3-mini" ,
url : "https://api.ai.sap" ,
npm : "@jerome-benoit/sap-ai-provider-v2" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( Object . keys ( result ) ) . toEqual ( [ "low" , "medium" , "high" ] )
expect ( result . low ) . toEqual ( { reasoningEffort : "low" } )
expect ( result . high ) . toEqual ( { reasoningEffort : "high" } )
} )
test ( "sonar models return empty object" , ( ) = > {
const model = createMockModel ( {
id : "sap-ai-core/perplexity--sonar-pro" ,
providerID : "sap-ai-core" ,
api : {
id : "perplexity--sonar-pro" ,
url : "https://api.ai.sap" ,
npm : "@jerome-benoit/sap-ai-provider-v2" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( { } )
} )
test ( "mistral models return empty object" , ( ) = > {
const model = createMockModel ( {
id : "sap-ai-core/mistral--mistral-large" ,
providerID : "sap-ai-core" ,
api : {
id : "mistral--mistral-large" ,
url : "https://api.ai.sap" ,
npm : "@jerome-benoit/sap-ai-provider-v2" ,
} ,
} )
const result = ProviderTransform . variants ( model )
expect ( result ) . toEqual ( { } )
} )
} )
2025-12-30 22:37:32 +00:00
} )