feat(asset): implement asset path resolution and streamline file loading
- Introduced a new utility function `FindAsset` in `PlatformPaths` to locate asset files across multiple standard directories, enhancing flexibility in asset management. - Updated various components to utilize `FindAsset` for loading configuration and prompt files, replacing hardcoded search paths with a more robust solution. - Improved error handling and logging for asset loading failures, ensuring clearer feedback during runtime. - Refactored existing code in `gemini_ai_service`, `prompt_builder`, and `platform_paths` to leverage the new asset resolution mechanism, promoting code consistency and maintainability.
This commit is contained in:
@@ -11,13 +11,13 @@
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "absl/strings/strip.h"
|
||||
#include "util/platform_paths.h"
|
||||
|
||||
#ifdef YAZE_WITH_JSON
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include "httplib.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// OpenSSL initialization for HTTPS support
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
@@ -76,34 +76,29 @@ GeminiAIService::GeminiAIService(const GeminiConfig& config)
|
||||
std::cerr << "[DEBUG] Building system instruction..." << std::endl;
|
||||
}
|
||||
|
||||
// Try to load version-specific system prompt file
|
||||
// Try to load version-specific system prompt file using FindAsset
|
||||
std::string prompt_file;
|
||||
if (config_.prompt_version == "v3") {
|
||||
prompt_file = "assets/agent/system_prompt_v3.txt";
|
||||
prompt_file = "agent/system_prompt_v3.txt";
|
||||
} else if (config_.prompt_version == "v2") {
|
||||
prompt_file = "assets/agent/system_prompt_v2.txt";
|
||||
prompt_file = "agent/system_prompt_v2.txt";
|
||||
} else {
|
||||
prompt_file = "assets/agent/system_prompt.txt";
|
||||
prompt_file = "agent/system_prompt.txt";
|
||||
}
|
||||
|
||||
std::vector<std::string> search_paths = {
|
||||
prompt_file,
|
||||
"../" + prompt_file,
|
||||
"../../" + prompt_file
|
||||
};
|
||||
|
||||
auto prompt_path = util::PlatformPaths::FindAsset(prompt_file);
|
||||
bool loaded = false;
|
||||
for (const auto& path : search_paths) {
|
||||
std::ifstream file(path);
|
||||
|
||||
if (prompt_path.ok()) {
|
||||
std::ifstream file(prompt_path->string());
|
||||
if (file.good()) {
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
config_.system_instruction = buffer.str();
|
||||
if (config_.verbose) {
|
||||
std::cerr << "[DEBUG] Loaded prompt: " << path << std::endl;
|
||||
std::cerr << "[DEBUG] Loaded prompt: " << prompt_path->string() << std::endl;
|
||||
}
|
||||
loaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,38 +143,22 @@ std::string GeminiAIService::BuildFunctionCallSchemas() {
|
||||
return schemas;
|
||||
}
|
||||
|
||||
// Fallback: Search for function_schemas.json
|
||||
const std::vector<std::string> search_paths = {
|
||||
"assets/agent/function_schemas.json",
|
||||
"../assets/agent/function_schemas.json",
|
||||
"../../assets/agent/function_schemas.json",
|
||||
};
|
||||
// Fallback: Search for function_schemas.json using FindAsset
|
||||
auto schema_path_or = util::PlatformPaths::FindAsset("agent/function_schemas.json");
|
||||
|
||||
fs::path schema_path;
|
||||
bool found = false;
|
||||
|
||||
for (const auto& candidate : search_paths) {
|
||||
fs::path resolved = fs::absolute(candidate);
|
||||
if (fs::exists(resolved)) {
|
||||
schema_path = resolved;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
std::cerr << "⚠️ Function schemas file not found. Tried paths:" << std::endl;
|
||||
for (const auto& path : search_paths) {
|
||||
std::cerr << " - " << fs::absolute(path).string() << std::endl;
|
||||
if (!schema_path_or.ok()) {
|
||||
if (config_.verbose) {
|
||||
std::cerr << "⚠️ Function schemas file not found: "
|
||||
<< schema_path_or.status().message() << std::endl;
|
||||
}
|
||||
return "[]"; // Return empty array as fallback
|
||||
}
|
||||
|
||||
// Load and parse the JSON file
|
||||
std::ifstream file(schema_path);
|
||||
std::ifstream file(schema_path_or->string());
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "⚠️ Failed to open function schemas file: "
|
||||
<< schema_path.string() << std::endl;
|
||||
<< schema_path_or->string() << std::endl;
|
||||
return "[]";
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "util/platform_paths.h"
|
||||
#include "yaml-cpp/yaml.h"
|
||||
|
||||
namespace yaze {
|
||||
@@ -18,8 +19,6 @@ namespace cli {
|
||||
|
||||
namespace {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
bool IsYamlBool(const std::string& value) {
|
||||
const std::string lower = absl::AsciiStrToLower(value);
|
||||
return lower == "true" || lower == "false" || lower == "yes" ||
|
||||
@@ -64,44 +63,6 @@ nlohmann::json YamlToJson(const YAML::Node& node) {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<fs::path> BuildCatalogueSearchPaths(const std::string& explicit_path) {
|
||||
std::vector<fs::path> paths;
|
||||
if (!explicit_path.empty()) {
|
||||
paths.emplace_back(explicit_path);
|
||||
}
|
||||
|
||||
if (const char* env_path = std::getenv("YAZE_AGENT_CATALOGUE")) {
|
||||
if (*env_path != '\0') {
|
||||
paths.emplace_back(env_path);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to get executable directory for better path resolution
|
||||
fs::path exe_dir;
|
||||
try {
|
||||
exe_dir = fs::current_path();
|
||||
} catch (...) {
|
||||
exe_dir = ".";
|
||||
}
|
||||
|
||||
const std::vector<std::string> defaults = {
|
||||
"assets/agent/prompt_catalogue.yaml",
|
||||
"../assets/agent/prompt_catalogue.yaml",
|
||||
"../../assets/agent/prompt_catalogue.yaml",
|
||||
"../../../assets/agent/prompt_catalogue.yaml", // From build/bin/
|
||||
"../../../../assets/agent/prompt_catalogue.yaml", // From build/bin/yaze.app/Contents/MacOS/
|
||||
"../Resources/assets/agent/prompt_catalogue.yaml", // macOS app bundle
|
||||
"assets/z3ed/prompt_catalogue.yaml",
|
||||
"../assets/z3ed/prompt_catalogue.yaml",
|
||||
};
|
||||
|
||||
for (const auto& candidate : defaults) {
|
||||
paths.emplace_back(candidate);
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PromptBuilder::PromptBuilder() = default;
|
||||
@@ -116,35 +77,35 @@ void PromptBuilder::ClearCatalogData() {
|
||||
|
||||
absl::StatusOr<std::string> PromptBuilder::ResolveCataloguePath(
|
||||
const std::string& yaml_path) const {
|
||||
const auto search_paths = BuildCatalogueSearchPaths(yaml_path);
|
||||
for (const auto& candidate : search_paths) {
|
||||
fs::path resolved = candidate;
|
||||
if (resolved.is_relative()) {
|
||||
try {
|
||||
resolved = fs::absolute(resolved);
|
||||
} catch (const std::exception& e) {
|
||||
// If we can't resolve the absolute path (e.g., cwd doesn't exist),
|
||||
// just try the relative path as-is
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (fs::exists(resolved)) {
|
||||
return resolved.string();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
// If checking existence fails, just continue to next path
|
||||
continue;
|
||||
// If an explicit path is provided, check it first
|
||||
if (!yaml_path.empty()) {
|
||||
std::error_code ec;
|
||||
if (std::filesystem::exists(yaml_path, ec) && !ec) {
|
||||
return yaml_path;
|
||||
}
|
||||
}
|
||||
|
||||
return absl::NotFoundError(
|
||||
absl::StrCat("Prompt catalogue not found. Checked paths: ",
|
||||
absl::StrJoin(search_paths, ", ",
|
||||
[](std::string* out, const fs::path& path) {
|
||||
absl::StrAppend(out, path.string());
|
||||
})));
|
||||
|
||||
// Check environment variable override
|
||||
if (const char* env_path = std::getenv("YAZE_AGENT_CATALOGUE")) {
|
||||
if (*env_path != '\0') {
|
||||
std::error_code ec;
|
||||
if (std::filesystem::exists(env_path, ec) && !ec) {
|
||||
return std::string(env_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use PlatformPaths to find the asset in standard locations
|
||||
// Try the requested path (default is prompt_catalogue.yaml)
|
||||
std::string relative_path = yaml_path.empty() ?
|
||||
"agent/prompt_catalogue.yaml" : yaml_path;
|
||||
|
||||
auto result = util::PlatformPaths::FindAsset(relative_path);
|
||||
if (result.ok()) {
|
||||
return result->string();
|
||||
}
|
||||
|
||||
return result.status();
|
||||
}
|
||||
|
||||
absl::Status PromptBuilder::LoadResourceCatalogue(const std::string& yaml_path) {
|
||||
@@ -548,15 +509,10 @@ std::string PromptBuilder::BuildFewShotExamplesSection() const {
|
||||
}
|
||||
|
||||
std::string PromptBuilder::BuildConstraintsSection() const {
|
||||
// Try to load from file first
|
||||
const std::vector<std::string> search_paths = {
|
||||
"assets/agent/tool_calling_instructions.txt",
|
||||
"../assets/agent/tool_calling_instructions.txt",
|
||||
"../../assets/agent/tool_calling_instructions.txt",
|
||||
};
|
||||
|
||||
for (const auto& path : search_paths) {
|
||||
std::ifstream file(path);
|
||||
// Try to load from file first using FindAsset
|
||||
auto file_path = util::PlatformPaths::FindAsset("agent/tool_calling_instructions.txt");
|
||||
if (file_path.ok()) {
|
||||
std::ifstream file(file_path->string());
|
||||
if (file.is_open()) {
|
||||
std::string content((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
@@ -743,15 +699,10 @@ std::string PromptBuilder::BuildContextSection(const RomContext& context) {
|
||||
}
|
||||
|
||||
std::string PromptBuilder::BuildSystemInstruction() {
|
||||
// Try to load from file first
|
||||
const std::vector<std::string> search_paths = {
|
||||
"assets/agent/system_prompt.txt",
|
||||
"../assets/agent/system_prompt.txt",
|
||||
"../../assets/agent/system_prompt.txt",
|
||||
};
|
||||
|
||||
for (const auto& path : search_paths) {
|
||||
std::ifstream file(path);
|
||||
// Try to load from file first using FindAsset
|
||||
auto file_path = util::PlatformPaths::FindAsset("agent/system_prompt.txt");
|
||||
if (file_path.ok()) {
|
||||
std::ifstream file(file_path->string());
|
||||
if (file.is_open()) {
|
||||
std::string content((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
@@ -876,3 +827,4 @@ std::vector<FewShotExample> PromptBuilder::GetExamplesForCategory(
|
||||
|
||||
} // namespace cli
|
||||
} // namespace yaze
|
||||
|
||||
|
||||
@@ -89,9 +89,11 @@ add_executable(
|
||||
cli/service/testing/test_suite_writer.cc
|
||||
)
|
||||
|
||||
# ============================================================================
|
||||
target_compile_definitions(z3ed PRIVATE YAZE_ASSETS_PATH="${CMAKE_SOURCE_DIR}/assets")
|
||||
|
||||
# ============================================================================
|
||||
# AI Agent Support (Consolidated via Z3ED_AI flag)
|
||||
# ============================================================================
|
||||
# ============================================================================
|
||||
if(Z3ED_AI OR YAZE_WITH_JSON)
|
||||
target_compile_definitions(z3ed PRIVATE YAZE_WITH_JSON)
|
||||
message(STATUS "✓ z3ed AI agent enabled (Ollama + Gemini support)")
|
||||
@@ -100,9 +102,9 @@ if(Z3ED_AI OR YAZE_WITH_JSON)
|
||||
target_link_libraries(z3ed PRIVATE nlohmann_json::nlohmann_json)
|
||||
endif()
|
||||
|
||||
# ============================================================================
|
||||
# ============================================================================
|
||||
# SSL/HTTPS Support (Optional - Required for Gemini API)
|
||||
# ============================================================================
|
||||
# ============================================================================
|
||||
# SSL is only enabled when AI features are active
|
||||
# Ollama (localhost) works without SSL, Gemini (HTTPS) requires it
|
||||
if((Z3ED_AI OR YAZE_WITH_JSON) AND (YAZE_WITH_GRPC OR Z3ED_AI))
|
||||
@@ -158,9 +160,9 @@ else()
|
||||
)
|
||||
endif()
|
||||
|
||||
# ============================================================================
|
||||
# ============================================================================
|
||||
# Optional gRPC Support for CLI Agent Test Command
|
||||
# ============================================================================
|
||||
# ============================================================================
|
||||
if(YAZE_WITH_GRPC)
|
||||
message(STATUS "Adding gRPC support to z3ed CLI")
|
||||
|
||||
@@ -183,4 +185,4 @@ if(YAZE_WITH_GRPC)
|
||||
libprotobuf)
|
||||
|
||||
message(STATUS "✓ gRPC CLI automation integrated")
|
||||
endif()
|
||||
endif()
|
||||
Reference in New Issue
Block a user