#ifndef BIERGARTEN_PIPELINE_INCLUDES_SERVICES_PROMPTING_PROMPT_DIRECTORY_H_ #define BIERGARTEN_PIPELINE_INCLUDES_SERVICES_PROMPTING_PROMPT_DIRECTORY_H_ /** * @file services/prompting/prompt_directory.h * @brief Interface and filesystem-backed implementation for named prompt * loading. * * Prompt files are resolved by key: a key of "BREWERY_GENERATION" maps to the * file /BREWERY_GENERATION.md. The interface is kept intentionally * narrow so test doubles can be injected without touching the filesystem. */ #include #include #include #include #include #include #include "services/logging/logger.h" /** * @brief Interface for loading named prompt files. */ class IPromptDirectory { public: IPromptDirectory() = default; IPromptDirectory(const IPromptDirectory&) = delete; IPromptDirectory& operator=(const IPromptDirectory&) = delete; IPromptDirectory(IPromptDirectory&&) = delete; IPromptDirectory& operator=(IPromptDirectory&&) = delete; virtual ~IPromptDirectory() = default; /** * @brief Loads the prompt associated with @p key. * * @param key Logical prompt key, e.g. "BREWERY_GENERATION". * @return Prompt text. * @throws std::runtime_error if the prompt file cannot be found or read. */ [[nodiscard]] virtual std::string Load(std::string_view key) = 0; }; /** * @brief Filesystem-backed IPromptDirectory implementation. * * Each call to Load() checks an in-process cache first, then reads * /.md from disk. The directory must exist and be readable * at construction time; individual file absence is reported lazily at Load(). */ class PromptDirectory final : public IPromptDirectory { public: /** * @brief Constructs a PromptDirectory rooted at @p prompt_dir. * * @param prompt_dir Absolute or relative path to the prompt directory. * @throws std::runtime_error if @p prompt_dir does not exist or is not a * directory. */ explicit PromptDirectory(const std::filesystem::path& prompt_dir); PromptDirectory(const std::filesystem::path& prompt_dir, std::shared_ptr logger); /** * @brief Loads the prompt for @p key, caching the result. * * Maps @p key → /.md. * * @param key Logical prompt key. * @return Prompt text. * @throws std::runtime_error if the file does not exist or is empty. */ [[nodiscard]] std::string Load(std::string_view key) override; private: std::filesystem::path prompt_dir_; std::shared_ptr logger_; std::unordered_map cache_; }; #endif // BIERGARTEN_PIPELINE_INCLUDES_SERVICES_PROMPTING_PROMPT_DIRECTORY_H_