Skip to content

Commit b62754d

Browse files
committed
fix: update CNCF model detection to use artifactType field in manifest
1 parent 0843b41 commit b62754d

File tree

3 files changed

+17
-2
lines changed

3 files changed

+17
-2
lines changed

pkg/distribution/internal/bundle/unpack.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,16 @@ func isV02Model(model types.ModelArtifact) bool {
4040
}
4141

4242
// isCNCFModel checks if the model was packaged using the CNCF ModelPack format.
43+
// Detection uses the manifest's artifactType field, which is required by the
44+
// CNCF model-spec ("application/vnd.cncf.model.manifest.v1+json").
4345
// CNCF ModelPack uses a layer-per-file approach with filepath annotations,
4446
// similar to V0.2, so it can be unpacked using UnpackFromLayers.
4547
func isCNCFModel(model types.ModelArtifact) bool {
4648
manifest, err := model.Manifest()
4749
if err != nil {
4850
return false
4951
}
50-
return manifest.Config.MediaType == modelpack.MediaTypeModelConfigV1
52+
return manifest.ArtifactType == modelpack.ArtifactTypeModelManifest
5153
}
5254

5355
// unpackLegacy is the original V0.1 unpacking logic that uses model.GGUFPaths(), model.SafetensorsPaths(), etc.

pkg/distribution/internal/bundle/unpack_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,13 @@ func TestIsCNCFModel(t *testing.T) {
235235
tests := []struct {
236236
name string
237237
configMediaType oci.MediaType
238+
artifactType string
238239
expected bool
239240
}{
240241
{
241242
name: "CNCF ModelPack config V1",
242243
configMediaType: modelpack.MediaTypeModelConfigV1,
244+
artifactType: modelpack.ArtifactTypeModelManifest,
243245
expected: true,
244246
},
245247
{
@@ -256,9 +258,10 @@ func TestIsCNCFModel(t *testing.T) {
256258

257259
for _, tt := range tests {
258260
t.Run(tt.name, func(t *testing.T) {
259-
// Create a minimal artifact with the given config media type
261+
// Create a minimal artifact with the given config media type and artifact type
260262
artifact := &testArtifactWithConfigMediaType{
261263
configMediaType: tt.configMediaType,
264+
artifactType: tt.artifactType,
262265
}
263266
result := isCNCFModel(artifact)
264267
if result != tt.expected {
@@ -271,10 +274,12 @@ func TestIsCNCFModel(t *testing.T) {
271274
// testArtifactWithConfigMediaType is a minimal ModelArtifact for testing isCNCFModel/isV02Model.
272275
type testArtifactWithConfigMediaType struct {
273276
configMediaType oci.MediaType
277+
artifactType string
274278
}
275279

276280
func (a *testArtifactWithConfigMediaType) Manifest() (*oci.Manifest, error) {
277281
return &oci.Manifest{
282+
ArtifactType: a.artifactType,
278283
Config: oci.Descriptor{
279284
MediaType: a.configMediaType,
280285
},

pkg/distribution/internal/partial/partial.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,13 +357,21 @@ func ManifestForLayers(i WithLayers) (*oci.Manifest, error) {
357357
return nil, fmt.Errorf("get layers: %w", err)
358358
}
359359

360+
type descriptorProvider interface {
361+
GetDescriptor() oci.Descriptor
362+
}
363+
360364
var layers []oci.Descriptor
361365
for _, l := range ls {
362366
// Check if this is our Layer type which embeds the full descriptor
363367
// with annotations.
364368
if layer, ok := l.(*Layer); ok {
365369
// Use the embedded descriptor directly to preserve annotations.
366370
layers = append(layers, layer.Descriptor)
371+
} else if dp, ok := l.(descriptorProvider); ok {
372+
// Use GetDescriptor() to preserve annotations from wrapper
373+
// types like remappedLayer.
374+
layers = append(layers, dp.GetDescriptor())
367375
} else {
368376
// Fall back to computing descriptor for other layer types.
369377
mt, err := l.MediaType()

0 commit comments

Comments
 (0)