2026-10-04 00:56:14 +00:00
|
|
|
package llm
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"sort"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
|
2026-11-10 16:13:53 +00:00
|
|
|
ck "go.maximumdirect.net/configkit"
|
|
|
|
|
pk "go.maximumdirect.net/promptkit"
|
2026-10-04 00:56:14 +00:00
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
|
)
|
|
|
|
|
|
2026-11-10 16:13:53 +00:00
|
|
|
func capturedSourcePaths(engine *pk.Engine, hostRoot string) ([]string, error) {
|
2026-10-04 00:56:14 +00:00
|
|
|
inspection, err := engine.InspectConfiguration()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("inspect configuration: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sources := inspection.Sources()
|
|
|
|
|
byID := make(map[string]ck.SourceInfo, len(sources))
|
|
|
|
|
paths := make(map[string]struct{}, len(sources))
|
2026-11-10 16:13:53 +00:00
|
|
|
hostPath := func(source ck.SourceInfo) string {
|
|
|
|
|
if source.Kind == ck.SourceKindFile {
|
|
|
|
|
return source.Path
|
|
|
|
|
}
|
|
|
|
|
if hostRoot != "" && source.Kind == ck.SourceKindFilesystem && strings.HasPrefix(source.Label, operatorFilesystem+"/") {
|
|
|
|
|
return filepath.Join(hostRoot, filepath.FromSlash(source.Path))
|
|
|
|
|
}
|
|
|
|
|
return ""
|
|
|
|
|
}
|
2026-10-04 00:56:14 +00:00
|
|
|
for _, source := range sources {
|
|
|
|
|
byID[source.ID] = source
|
2026-11-10 16:13:53 +00:00
|
|
|
if path := hostPath(source); path != "" {
|
|
|
|
|
paths[path] = struct{}{}
|
2026-10-04 00:56:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
metadata := inspection.Metadata()
|
|
|
|
|
for _, path := range metadata.HistoricalPaths() {
|
|
|
|
|
segments := strings.Split(strings.TrimPrefix(path.String(), "/"), "/")
|
2026-11-10 16:13:53 +00:00
|
|
|
// Prompt resources are lists at the root or inside a collection.
|
|
|
|
|
if len(segments) == 7 && segments[0] == "collections" {
|
|
|
|
|
segments = segments[2:]
|
|
|
|
|
}
|
|
|
|
|
if len(segments) != 5 || segments[0] != "prompts" || segments[2] != "messages" || segments[4] != "content_file" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if _, err := strconv.Atoi(segments[1]); err != nil {
|
2026-10-04 00:56:14 +00:00
|
|
|
continue
|
|
|
|
|
}
|
2026-11-10 16:13:53 +00:00
|
|
|
if _, err := strconv.Atoi(segments[3]); err != nil {
|
2026-10-04 00:56:14 +00:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
field, ok := metadata.Lookup(path)
|
|
|
|
|
if !ok || field.Null || len(field.Origin.Locations) != 1 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
source, ok := byID[field.Origin.Locations[0].SourceID]
|
2026-11-10 16:13:53 +00:00
|
|
|
if !ok || hostPath(source) == "" {
|
2026-10-04 00:56:14 +00:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
explanation, ok := inspection.Explain(path)
|
|
|
|
|
if !ok || !explanation.Effective.Present || explanation.Effective.Redacted {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
var resource string
|
|
|
|
|
if err := yaml.Unmarshal([]byte(explanation.Effective.YAML), &resource); err != nil {
|
|
|
|
|
return nil, fmt.Errorf("decode captured message resource at %s: %w", path.String(), err)
|
|
|
|
|
}
|
2026-11-10 16:13:53 +00:00
|
|
|
paths[filepath.Join(filepath.Dir(hostPath(source)), filepath.FromSlash(resource))] = struct{}{}
|
2026-10-04 00:56:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result := make([]string, 0, len(paths))
|
|
|
|
|
for path := range paths {
|
|
|
|
|
result = append(result, path)
|
|
|
|
|
}
|
|
|
|
|
sort.Strings(result)
|
|
|
|
|
return result, nil
|
|
|
|
|
}
|