@@ -16,14 +16,16 @@ import { Env } from "../env"
1616import { Instance } from "../project/instance"
1717import { InstallationVersion } from "../installation/version"
1818import { Flag } from "../flag/flag"
19+ import { zod } from "@/util/effect-zod"
1920import { iife } from "@/util/iife"
2021import { Global } from "../global"
2122import path from "path"
22- import { Effect , Layer , Context } from "effect"
23+ import { Effect , Layer , Context , Schema , Types } from "effect"
2324import { EffectBridge } from "@/effect"
2425import { InstanceState } from "@/effect"
2526import { AppFileSystem } from "@opencode-ai/shared/filesystem"
2627import { isRecord } from "@/util/record"
28+ import { withStatics } from "@/util/schema"
2729
2830import * as ProviderTransform from "./transform"
2931import { ModelID , ProviderID } from "./schema"
@@ -796,91 +798,111 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
796798 }
797799}
798800
799- export const Model = z
800- . object ( {
801- id : ModelID . zod ,
802- providerID : ProviderID . zod ,
803- api : z . object ( {
804- id : z . string ( ) ,
805- url : z . string ( ) ,
806- npm : z . string ( ) ,
807- } ) ,
808- name : z . string ( ) ,
809- family : z . string ( ) . optional ( ) ,
810- capabilities : z . object ( {
811- temperature : z . boolean ( ) ,
812- reasoning : z . boolean ( ) ,
813- attachment : z . boolean ( ) ,
814- toolcall : z . boolean ( ) ,
815- input : z . object ( {
816- text : z . boolean ( ) ,
817- audio : z . boolean ( ) ,
818- image : z . boolean ( ) ,
819- video : z . boolean ( ) ,
820- pdf : z . boolean ( ) ,
821- } ) ,
822- output : z . object ( {
823- text : z . boolean ( ) ,
824- audio : z . boolean ( ) ,
825- image : z . boolean ( ) ,
826- video : z . boolean ( ) ,
827- pdf : z . boolean ( ) ,
828- } ) ,
829- interleaved : z . union ( [
830- z . boolean ( ) ,
831- z . object ( {
832- field : z . enum ( [ "reasoning_content" , "reasoning_details" ] ) ,
833- } ) ,
834- ] ) ,
835- } ) ,
836- cost : z . object ( {
837- input : z . number ( ) ,
838- output : z . number ( ) ,
839- cache : z . object ( {
840- read : z . number ( ) ,
841- write : z . number ( ) ,
842- } ) ,
843- experimentalOver200K : z
844- . object ( {
845- input : z . number ( ) ,
846- output : z . number ( ) ,
847- cache : z . object ( {
848- read : z . number ( ) ,
849- write : z . number ( ) ,
850- } ) ,
851- } )
852- . optional ( ) ,
853- } ) ,
854- limit : z . object ( {
855- context : z . number ( ) ,
856- input : z . number ( ) . optional ( ) ,
857- output : z . number ( ) ,
801+ const ProviderApiInfo = Schema . Struct ( {
802+ id : Schema . String ,
803+ url : Schema . String ,
804+ npm : Schema . String ,
805+ } )
806+
807+ const ProviderModalities = Schema . Struct ( {
808+ text : Schema . Boolean ,
809+ audio : Schema . Boolean ,
810+ image : Schema . Boolean ,
811+ video : Schema . Boolean ,
812+ pdf : Schema . Boolean ,
813+ } )
814+
815+ const ProviderInterleaved = Schema . Union ( [
816+ Schema . Boolean ,
817+ Schema . Struct ( {
818+ field : Schema . Literals ( [ "reasoning_content" , "reasoning_details" ] ) ,
819+ } ) ,
820+ ] )
821+
822+ const ProviderCapabilities = Schema . Struct ( {
823+ temperature : Schema . Boolean ,
824+ reasoning : Schema . Boolean ,
825+ attachment : Schema . Boolean ,
826+ toolcall : Schema . Boolean ,
827+ input : ProviderModalities ,
828+ output : ProviderModalities ,
829+ interleaved : ProviderInterleaved ,
830+ } )
831+
832+ const ProviderCacheCost = Schema . Struct ( {
833+ read : Schema . Number ,
834+ write : Schema . Number ,
835+ } )
836+
837+ const ProviderCost = Schema . Struct ( {
838+ input : Schema . Number ,
839+ output : Schema . Number ,
840+ cache : ProviderCacheCost ,
841+ experimentalOver200K : Schema . optional (
842+ Schema . Struct ( {
843+ input : Schema . Number ,
844+ output : Schema . Number ,
845+ cache : ProviderCacheCost ,
858846 } ) ,
859- status : z . enum ( [ "alpha" , "beta" , "deprecated" , "active" ] ) ,
860- options : z . record ( z . string ( ) , z . any ( ) ) ,
861- headers : z . record ( z . string ( ) , z . string ( ) ) ,
862- release_date : z . string ( ) ,
863- variants : z . record ( z . string ( ) , z . record ( z . string ( ) , z . any ( ) ) ) . optional ( ) ,
864- } )
865- . meta ( {
866- ref : "Model" ,
867- } )
868- export type Model = z . infer < typeof Model >
869-
870- export const Info = z
871- . object ( {
872- id : ProviderID . zod ,
873- name : z . string ( ) ,
874- source : z . enum ( [ "env" , "config" , "custom" , "api" ] ) ,
875- env : z . string ( ) . array ( ) ,
876- key : z . string ( ) . optional ( ) ,
877- options : z . record ( z . string ( ) , z . any ( ) ) ,
878- models : z . record ( z . string ( ) , Model ) ,
879- } )
880- . meta ( {
881- ref : "Provider" ,
882- } )
883- export type Info = z . infer < typeof Info >
847+ ) ,
848+ } )
849+
850+ const ProviderLimit = Schema . Struct ( {
851+ context : Schema . Number ,
852+ input : Schema . optional ( Schema . Number ) ,
853+ output : Schema . Number ,
854+ } )
855+
856+ export const Model = Schema . Struct ( {
857+ id : ModelID ,
858+ providerID : ProviderID ,
859+ api : ProviderApiInfo ,
860+ name : Schema . String ,
861+ family : Schema . optional ( Schema . String ) ,
862+ capabilities : ProviderCapabilities ,
863+ cost : ProviderCost ,
864+ limit : ProviderLimit ,
865+ status : Schema . Literals ( [ "alpha" , "beta" , "deprecated" , "active" ] ) ,
866+ options : Schema . Record ( Schema . String , Schema . Any ) ,
867+ headers : Schema . Record ( Schema . String , Schema . String ) ,
868+ release_date : Schema . String ,
869+ variants : Schema . optional ( Schema . Record ( Schema . String , Schema . Record ( Schema . String , Schema . Any ) ) ) ,
870+ } )
871+ . annotate ( { identifier : "Model" } )
872+ . pipe ( withStatics ( ( s ) => ( { zod : zod ( s ) } ) ) )
873+ export type Model = Types . DeepMutable < Schema . Schema . Type < typeof Model > >
874+
875+ export const Info = Schema . Struct ( {
876+ id : ProviderID ,
877+ name : Schema . String ,
878+ source : Schema . Literals ( [ "env" , "config" , "custom" , "api" ] ) ,
879+ env : Schema . Array ( Schema . String ) ,
880+ key : Schema . optional ( Schema . String ) ,
881+ options : Schema . Record ( Schema . String , Schema . Any ) ,
882+ models : Schema . Record ( Schema . String , Model ) ,
883+ } )
884+ . annotate ( { identifier : "Provider" } )
885+ . pipe ( withStatics ( ( s ) => ( { zod : zod ( s ) } ) ) )
886+ export type Info = Types . DeepMutable < Schema . Schema . Type < typeof Info > >
887+
888+ const DefaultModelIDs = Schema . Record ( Schema . String , Schema . String )
889+
890+ export const ListResult = Schema . Struct ( {
891+ all : Schema . Array ( Info ) ,
892+ default : DefaultModelIDs ,
893+ connected : Schema . Array ( Schema . String ) ,
894+ } ) . pipe ( withStatics ( ( s ) => ( { zod : zod ( s ) } ) ) )
895+ export type ListResult = Types . DeepMutable < Schema . Schema . Type < typeof ListResult > >
896+
897+ export const ConfigProvidersResult = Schema . Struct ( {
898+ providers : Schema . Array ( Info ) ,
899+ default : DefaultModelIDs ,
900+ } ) . pipe ( withStatics ( ( s ) => ( { zod : zod ( s ) } ) ) )
901+ export type ConfigProvidersResult = Types . DeepMutable < Schema . Schema . Type < typeof ConfigProvidersResult > >
902+
903+ export function defaultModelIDs < T extends { models : Record < string , { id : string } > } > ( providers : Record < string , T > ) {
904+ return mapValues ( providers , ( item ) => sort ( Object . values ( item . models ) ) [ 0 ] . id )
905+ }
884906
885907export interface Interface {
886908 readonly list : ( ) => Effect . Effect < Record < ProviderID , Info > >
@@ -928,7 +950,7 @@ function cost(c: ModelsDev.Model["cost"]): Model["cost"] {
928950}
929951
930952function fromModelsDevModel ( provider : ModelsDev . Provider , model : ModelsDev . Model ) : Model {
931- const m : Model = {
953+ const base : Model = {
932954 id : ModelID . make ( model . id ) ,
933955 providerID : ProviderID . make ( provider . id ) ,
934956 name : model . name ,
@@ -972,9 +994,10 @@ function fromModelsDevModel(provider: ModelsDev.Provider, model: ModelsDev.Model
972994 variants : { } ,
973995 }
974996
975- m . variants = mapValues ( ProviderTransform . variants ( m ) , ( v ) => v )
976-
977- return m
997+ return {
998+ ...base ,
999+ variants : mapValues ( ProviderTransform . variants ( base ) , ( v ) => v ) ,
1000+ }
9781001}
9791002
9801003export function fromModelsDevProvider ( provider : ModelsDev . Provider ) : Info {
@@ -983,17 +1006,22 @@ export function fromModelsDevProvider(provider: ModelsDev.Provider): Info {
9831006 models [ key ] = fromModelsDevModel ( provider , model )
9841007 for ( const [ mode , opts ] of Object . entries ( model . experimental ?. modes ?? { } ) ) {
9851008 const id = `${ model . id } -${ mode } `
986- const m = fromModelsDevModel ( provider , model )
987- m . id = ModelID . make ( id )
988- m . name = `${ model . name } ${ mode [ 0 ] . toUpperCase ( ) } ${ mode . slice ( 1 ) } `
989- if ( opts . cost ) m . cost = mergeDeep ( m . cost , cost ( opts . cost ) )
990- // convert body params to camelCase for ai sdk compatibility
991- if ( opts . provider ?. body )
992- m . options = Object . fromEntries (
993- Object . entries ( opts . provider . body ) . map ( ( [ k , v ] ) => [ k . replace ( / _ ( [ a - z ] ) / g, ( _ , c ) => c . toUpperCase ( ) ) , v ] ) ,
994- )
995- if ( opts . provider ?. headers ) m . headers = opts . provider . headers
996- models [ id ] = m
1009+ const base = fromModelsDevModel ( provider , model )
1010+ models [ id ] = {
1011+ ...base ,
1012+ id : ModelID . make ( id ) ,
1013+ name : `${ model . name } ${ mode [ 0 ] . toUpperCase ( ) } ${ mode . slice ( 1 ) } ` ,
1014+ cost : opts . cost ? mergeDeep ( base . cost , cost ( opts . cost ) ) : base . cost ,
1015+ options : opts . provider ?. body
1016+ ? Object . fromEntries (
1017+ Object . entries ( opts . provider . body ) . map ( ( [ k , v ] ) => [
1018+ k . replace ( / _ ( [ a - z ] ) / g, ( _ , c ) => c . toUpperCase ( ) ) ,
1019+ v ,
1020+ ] ) ,
1021+ )
1022+ : base . options ,
1023+ headers : opts . provider ?. headers ?? base . headers ,
1024+ }
9971025 }
9981026 }
9991027 return {
0 commit comments