@@ -90,7 +90,9 @@ func BuildModel(ctx context.Context, client *Client, repo, revision, tag string,
9090 _ = progress .WriteProgress (progressWriter , "Building model artifact..." , 0 , 0 , 0 , "" , "pull" )
9191 }
9292
93- model , err := buildModelFromFiles (result .LocalPaths , weightFiles , configFiles , tempDir , createdTime )
93+ model , err := buildModelFromFiles (
94+ result .LocalPaths , weightFiles , configFiles , mmprojFile , tempDir , createdTime ,
95+ )
9496 if err != nil {
9597 return nil , fmt .Errorf ("build model: %w" , err )
9698 }
@@ -103,14 +105,20 @@ func BuildModel(ctx context.Context, client *Client, repo, revision, tag string,
103105// which preserves directory structure and adds each file as an individual layer with
104106// filepath annotations. For GGUF models, it uses the V0.1 packaging (FromPaths)
105107// for backward compatibility.
106- func buildModelFromFiles (localPaths map [string ]string , weightFiles , configFiles []RepoFile , tempDir string , createdTime * time.Time ) (types.ModelArtifact , error ) {
108+ func buildModelFromFiles (
109+ localPaths map [string ]string ,
110+ weightFiles , configFiles []RepoFile ,
111+ mmprojFile * RepoFile ,
112+ tempDir string ,
113+ createdTime * time.Time ,
114+ ) (types.ModelArtifact , error ) {
107115 // Check if this is a safetensors model - use V0.2 packaging
108116 if isSafetensorsModel (weightFiles ) {
109117 return buildSafetensorsModelV02 (tempDir , createdTime )
110118 }
111119
112120 // For GGUF models, use V0.1 packaging (backward compatible)
113- return buildGGUFModelV01 (localPaths , weightFiles , configFiles , createdTime )
121+ return buildGGUFModelV01 (localPaths , weightFiles , configFiles , mmprojFile , createdTime )
114122}
115123
116124// buildSafetensorsModelV02 builds a safetensors model using V0.2 layer-per-file packaging.
@@ -133,7 +141,12 @@ func buildSafetensorsModelV02(tempDir string, createdTime *time.Time) (types.Mod
133141}
134142
135143// buildGGUFModelV01 builds a GGUF model using V0.1 packaging (backward compatible).
136- func buildGGUFModelV01 (localPaths map [string ]string , weightFiles , configFiles []RepoFile , createdTime * time.Time ) (types.ModelArtifact , error ) {
144+ func buildGGUFModelV01 (
145+ localPaths map [string ]string ,
146+ weightFiles , configFiles []RepoFile ,
147+ mmprojFile * RepoFile ,
148+ createdTime * time.Time ,
149+ ) (types.ModelArtifact , error ) {
137150 // Collect weight file paths (sorted for reproducibility)
138151 var weightPaths []string
139152 for _ , f := range weightFiles {
@@ -157,7 +170,19 @@ func buildGGUFModelV01(localPaths map[string]string, weightFiles, configFiles []
157170 return nil , fmt .Errorf ("create builder: %w" , err )
158171 }
159172
160- // Check for chat template and add it
173+ // Add multimodal projector if present (F16 preferred, selected upstream).
174+ if mmprojFile != nil {
175+ localPath , ok := localPaths [mmprojFile .Path ]
176+ if ! ok {
177+ return nil , fmt .Errorf ("missing local path for mmproj %s" , mmprojFile .Path )
178+ }
179+ b , err = b .WithMultimodalProjector (localPath )
180+ if err != nil {
181+ return nil , fmt .Errorf ("add mmproj: %w" , err )
182+ }
183+ }
184+
185+ // Check for chat template and add it.
161186 for _ , f := range configFiles {
162187 if isChatTemplate (f .Path ) {
163188 localPath := localPaths [f .Path ]
0 commit comments