@@ -18,6 +18,7 @@ import (
1818 "context"
1919 "errors"
2020 "fmt"
21+ "io/fs"
2122 "log/slog"
2223 "maps"
2324 "os"
@@ -505,12 +506,17 @@ func LoadPromptDir(r api.Registry, dir string, namespace string) {
505506 return
506507 }
507508
508- loadPromptDir (r , path , namespace )
509+ loadPromptDir (r , os .DirFS (dir ), "." , namespace )
510+ }
511+
512+ // LoadPromptFS loads prompts and partials from the given filesystem for the given namespace.
513+ func LoadPromptFS (r api.Registry , fsys fs.FS , dir string , namespace string ) {
514+ loadPromptDir (r , fsys , dir , namespace )
509515}
510516
511517// loadPromptDir recursively loads prompts and partials from the directory.
512- func loadPromptDir (r api.Registry , dir string , namespace string ) {
513- entries , err := os .ReadDir (dir )
518+ func loadPromptDir (r api.Registry , fsys fs. FS , dir , namespace string ) {
519+ entries , err := fs .ReadDir (fsys , dir )
514520 if err != nil {
515521 panic (fmt .Errorf ("failed to read prompt directory structure: %w" , err ))
516522 }
@@ -519,7 +525,7 @@ func loadPromptDir(r api.Registry, dir string, namespace string) {
519525 filename := entry .Name ()
520526 path := filepath .Join (dir , filename )
521527 if entry .IsDir () {
522- loadPromptDir (r , path , namespace )
528+ loadPromptDir (r , fsys , path , namespace )
523529 } else if strings .HasSuffix (filename , ".prompt" ) {
524530 if strings .HasPrefix (filename , "_" ) {
525531 partialName := strings .TrimSuffix (filename [1 :], ".prompt" )
@@ -531,19 +537,25 @@ func loadPromptDir(r api.Registry, dir string, namespace string) {
531537 r .RegisterPartial (partialName , string (source ))
532538 slog .Debug ("Registered Dotprompt partial" , "name" , partialName , "file" , path )
533539 } else {
534- LoadPrompt ( r , dir , filename , namespace )
540+ loadPrompt ( r , fsys , dir , filename , namespace )
535541 }
536542 }
537543 }
538544}
539545
540546// LoadPrompt loads a single prompt into the registry.
541547func LoadPrompt (r api.Registry , dir , filename , namespace string ) Prompt {
548+ dir , rest := filepath .Split (dir )
549+ return loadPrompt (r , os .DirFS (dir ), rest , filename , namespace )
550+ }
551+
552+ // loadPrompt uses provided fsys to load a single prompt into the registry.
553+ func loadPrompt (r api.Registry , fsys fs.FS , dir , filename , namespace string ) Prompt {
542554 name := strings .TrimSuffix (filename , ".prompt" )
543555 name , variant , _ := strings .Cut (name , "." )
544556
545557 sourceFile := filepath .Join (dir , filename )
546- source , err := os .ReadFile (sourceFile )
558+ source , err := fs .ReadFile (fsys , sourceFile )
547559 if err != nil {
548560 slog .Error ("Failed to read prompt file" , "file" , sourceFile , "error" , err )
549561 return nil
0 commit comments