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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion pkg/cmd/inspect/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,14 @@ func getInspectInfo(ctx context.Context, repository oras.Target, ref string) (*i
return nil, err
}
version := "unknown"
if manifest.Annotations != nil && manifest.Annotations[constants.CliVersionAnnotation] != "" {
if manifest.Annotations != nil {
version = manifest.Annotations[constants.CliVersionAnnotation]
if version == "" {
version = manifest.Annotations[constants.LegacyCliVersionAnnotation]
}
if version == "" {
version = "unknown"
}
}
return &inspectInfo{
Digest: desc.Digest,
Expand Down
18 changes: 12 additions & 6 deletions pkg/lib/constants/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,21 @@ const (
DevModelsSubpath = "dev-models"
CurrentDevModelSubpath = "current"

// Kitops-specific annotations for modelkit artifacts
// TODO: update these to use the newer kitops.org domain
CliVersionAnnotation = "ml.kitops.modelkit.cli-version"
KitfileJsonAnnotation = "ml.kitops.modelkit.kitfile"
// KitOps-specific annotations for ModelKit artifacts.
// Canonical keys use the reverse-DNS form of kitops.org.
CliVersionAnnotation = "org.kitops.modelkit.cli-version"
KitfileJsonAnnotation = "org.kitops.modelkit.kitfile"

// Legacy annotation keys kept for backwards compatibility when reading/writing
// manifests produced by older CLI versions.
LegacyCliVersionAnnotation = "ml.kitops.modelkit.cli-version"
LegacyKitfileJsonAnnotation = "ml.kitops.modelkit.kitfile"

// LayerSubtypeAnnotation stores additional type information for a given OCI manifest
// layer within its annotations (e.g. storing prompts within code-type layers)
LayerSubtypeAnnotation = "ml.kitops.modelkit.layer-subtype"
LayerSubtypePrompt = "prompt"
LayerSubtypeAnnotation = "org.kitops.modelkit.layer-subtype"
LegacyLayerSubtypeAnnotation = "ml.kitops.modelkit.layer-subtype"
LayerSubtypePrompt = "prompt"

// MaxModelRefChain is the maximum number of "parent" modelkits a modelkit may have
// by e.g. referring to another modelkit in its .model.path
Expand Down
13 changes: 10 additions & 3 deletions pkg/lib/external/git/clone.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package git
import (
"errors"
"fmt"
"io"
"io/fs"
"os"
"os/exec"
Expand Down Expand Up @@ -113,13 +114,19 @@ func checkDestination(path string) error {
if !stat.IsDir() {
return fmt.Errorf("path %s exists and is not a directory", path)
}
// TODO: probably don't need to read the _whole_ directory
contents, err := os.ReadDir(path)
// Only check whether at least one entry exists; avoid reading full directory.
dir, err := os.Open(path)
if err != nil {
return fmt.Errorf("failed to inspect directory %s: %w", path, err)
}
if len(contents) > 0 {
defer dir.Close()

_, err = dir.ReadDir(1)
if err == nil {
return fmt.Errorf("cannot clone to a non-empty directory")
}
if !errors.Is(err, io.EOF) {
return fmt.Errorf("failed to inspect directory %s: %w", path, err)
}
return nil
}
3 changes: 3 additions & 0 deletions pkg/lib/filesystem/local-storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func SaveModel(ctx context.Context, localRepo local.LocalRepo, kitfile *artifact
manifest.Annotations = map[string]string{}
}
manifest.Annotations[constants.KitfileJsonAnnotation] = string(kitfileBytes)
manifest.Annotations[constants.LegacyKitfileJsonAnnotation] = string(kitfileBytes)
}

manifestDesc, err := saveModelManifest(ctx, localRepo, manifest)
Expand Down Expand Up @@ -211,6 +212,7 @@ func saveKitfileLayers(ctx context.Context, localRepo local.LocalRepo, kitfile *
layer.Annotations = map[string]string{}
}
layer.Annotations[constants.LayerSubtypeAnnotation] = constants.LayerSubtypePrompt
layer.Annotations[constants.LegacyLayerSubtypeAnnotation] = constants.LayerSubtypePrompt
layers = append(layers, layer)
diffIDs = append(diffIDs, digest.FromString(layerInfo.DiffId))
kitfile.Prompts[idx].LayerInfo = layerInfo
Expand Down Expand Up @@ -345,6 +347,7 @@ func createManifest(configDesc ocispec.Descriptor, layerDescs []ocispec.Descript
manifest.Annotations = map[string]string{}
}
manifest.Annotations[constants.CliVersionAnnotation] = constants.Version
manifest.Annotations[constants.LegacyCliVersionAnnotation] = constants.Version

return manifest, nil
}
6 changes: 5 additions & 1 deletion pkg/lib/filesystem/unpack/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@ func unpackRecursive(ctx context.Context, opts *UnpackOptions, visitedRefs []str

case mediatype.CodeBaseType:
// Code-type layers may be either regular code or prompts
if layerDesc.Annotations[constants.LayerSubtypeAnnotation] == constants.LayerSubtypePrompt {
subtype := layerDesc.Annotations[constants.LayerSubtypeAnnotation]
if subtype == "" {
subtype = layerDesc.Annotations[constants.LegacyLayerSubtypeAnnotation]
}
if subtype == constants.LayerSubtypePrompt {
entry := config.Prompts[promptIdx]
promptIdx += 1
if !kitfile.LayerMatchesAnyFilter(entry, opts.FilterConfs) {
Expand Down
8 changes: 7 additions & 1 deletion pkg/lib/repo/util/reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,16 @@ func GetKitfileForManifest(ctx context.Context, store oras.ReadOnlyTarget, manif
return GetConfig(ctx, store, manifest.Config)
case mediatype.ModelPackFormat:
// TODO: can we (try to) generate a Kitfile from a ModelPack manifest?
if manifest.Annotations == nil || manifest.Annotations[constants.KitfileJsonAnnotation] == "" {
if manifest.Annotations == nil {
return nil, ErrNoKitfile
}
kfstring := manifest.Annotations[constants.KitfileJsonAnnotation]
if kfstring == "" {
kfstring = manifest.Annotations[constants.LegacyKitfileJsonAnnotation]
}
if kfstring == "" {
return nil, ErrNoKitfile
}
kitfile := &artifact.KitFile{}
if err := json.Unmarshal([]byte(kfstring), kitfile); err != nil {
return nil, fmt.Errorf("failed to parse config: %w", err)
Expand Down