Keep checkpoints aligned with PromptKit profiles
This commit is contained in:
82
internal/framework/llm/promptkit_profile_fingerprint.go
Normal file
82
internal/framework/llm/promptkit_profile_fingerprint.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package llm
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
promptKitProfileFingerprintName = "promptkit_profile_source"
|
||||
// The built-in profile catalog is compiled into this pinned PromptKit
|
||||
// release. Update this identity when the dependency is upgraded.
|
||||
promptKitBuiltinProfileCatalogID = "promptkit:v0.1.0:builtin-profiles"
|
||||
)
|
||||
|
||||
func promptKitProfileFingerprint(profileDir, profileFile string) (CheckpointFingerprint, error) {
|
||||
hasher := sha256.New()
|
||||
writeFingerprintPart(hasher, []byte(promptKitBuiltinProfileCatalogID))
|
||||
|
||||
switch {
|
||||
case strings.TrimSpace(profileFile) != "":
|
||||
data, err := os.ReadFile(strings.TrimSpace(profileFile))
|
||||
if err != nil {
|
||||
return CheckpointFingerprint{}, fmt.Errorf("read PromptKit profile file for checkpoint identity: %w", err)
|
||||
}
|
||||
writeFingerprintPart(hasher, data)
|
||||
case strings.TrimSpace(profileDir) != "":
|
||||
digests, err := promptKitProfileFileDigests(strings.TrimSpace(profileDir))
|
||||
if err != nil {
|
||||
return CheckpointFingerprint{}, err
|
||||
}
|
||||
for _, digest := range digests {
|
||||
writeFingerprintPart(hasher, digest)
|
||||
}
|
||||
}
|
||||
|
||||
return CheckpointFingerprint{
|
||||
Name: promptKitProfileFingerprintName,
|
||||
Value: "sha256:" + hex.EncodeToString(hasher.Sum(nil)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func promptKitProfileFileDigests(root string) ([][]byte, error) {
|
||||
var digests [][]byte
|
||||
err := filepath.WalkDir(root, func(name string, entry fs.DirEntry, walkErr error) error {
|
||||
if walkErr != nil {
|
||||
return walkErr
|
||||
}
|
||||
if entry.IsDir() {
|
||||
return nil
|
||||
}
|
||||
extension := filepath.Ext(entry.Name())
|
||||
if extension != ".yaml" && extension != ".yml" {
|
||||
return nil
|
||||
}
|
||||
data, err := os.ReadFile(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sum := sha256.Sum256(data)
|
||||
digests = append(digests, append([]byte(nil), sum[:]...))
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read PromptKit profile directory for checkpoint identity: %w", err)
|
||||
}
|
||||
sort.Slice(digests, func(i, j int) bool {
|
||||
return string(digests[i]) < string(digests[j])
|
||||
})
|
||||
return digests, nil
|
||||
}
|
||||
|
||||
func writeFingerprintPart(hasher interface{ Write([]byte) (int, error) }, value []byte) {
|
||||
length := []byte(fmt.Sprintf("%d:", len(value)))
|
||||
_, _ = hasher.Write(length)
|
||||
_, _ = hasher.Write(value)
|
||||
}
|
||||
Reference in New Issue
Block a user