feat: Implement AgentChatWidget for conversational AI interaction and add ASCII logo support
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "app/core/asar_wrapper.h"
|
||||
#include "app/rom.h"
|
||||
#include "cli/z3ed_ascii_logo.h"
|
||||
|
||||
ABSL_DECLARE_FLAG(std::string, rom);
|
||||
|
||||
@@ -249,7 +250,7 @@ void ModernCLI::SetupCommands() {
|
||||
}
|
||||
|
||||
void ModernCLI::ShowHelp() {
|
||||
std::cout << "z3ed - Yet Another Zelda3 Editor CLI Tool" << std::endl;
|
||||
std::cout << GetColoredLogo() << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "USAGE:" << std::endl;
|
||||
std::cout << " z3ed [--tui] <resource> <action> [arguments]" << std::endl;
|
||||
|
||||
@@ -11,15 +11,18 @@
|
||||
#include "absl/strings/strip.h"
|
||||
|
||||
#ifdef YAZE_WITH_JSON
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include "httplib.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
namespace fs = std::filesystem;
|
||||
#endif
|
||||
|
||||
namespace yaze {
|
||||
namespace cli {
|
||||
|
||||
GeminiAIService::GeminiAIService(const GeminiConfig& config)
|
||||
: config_(config) {
|
||||
: config_(config), function_calling_enabled_(true) {
|
||||
// Load command documentation into prompt builder
|
||||
if (auto status = prompt_builder_.LoadResourceCatalogue(""); !status.ok()) {
|
||||
std::cerr << "⚠️ Failed to load agent prompt catalogue: "
|
||||
@@ -36,6 +39,71 @@ GeminiAIService::GeminiAIService(const GeminiConfig& config)
|
||||
}
|
||||
}
|
||||
|
||||
void GeminiAIService::EnableFunctionCalling(bool enable) {
|
||||
function_calling_enabled_ = enable;
|
||||
}
|
||||
|
||||
std::vector<std::string> GeminiAIService::GetAvailableTools() const {
|
||||
return {
|
||||
"resource_list",
|
||||
"dungeon_list_sprites",
|
||||
"overworld_find_tile",
|
||||
"overworld_describe_map",
|
||||
"overworld_list_warps"
|
||||
};
|
||||
}
|
||||
|
||||
std::string GeminiAIService::BuildFunctionCallSchemas() {
|
||||
#ifndef YAZE_WITH_JSON
|
||||
return "[]"; // Empty array if JSON not available
|
||||
#else
|
||||
// Search for function_schemas.json in multiple locations
|
||||
const std::vector<std::string> search_paths = {
|
||||
"assets/agent/function_schemas.json",
|
||||
"../assets/agent/function_schemas.json",
|
||||
"../../assets/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;
|
||||
}
|
||||
return "[]"; // Return empty array as fallback
|
||||
}
|
||||
|
||||
// Load and parse the JSON file
|
||||
std::ifstream file(schema_path);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "⚠️ Failed to open function schemas file: "
|
||||
<< schema_path.string() << std::endl;
|
||||
return "[]";
|
||||
}
|
||||
|
||||
try {
|
||||
nlohmann::json schemas_json;
|
||||
file >> schemas_json;
|
||||
return schemas_json.dump();
|
||||
} catch (const nlohmann::json::exception& e) {
|
||||
std::cerr << "⚠️ Failed to parse function schemas JSON: "
|
||||
<< e.what() << std::endl;
|
||||
return "[]";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string GeminiAIService::BuildSystemInstruction() {
|
||||
// Fallback prompt if enhanced prompting is disabled
|
||||
// Use PromptBuilder's basic system instruction
|
||||
@@ -140,6 +208,18 @@ absl::StatusOr<AgentResponse> GeminiAIService::GenerateResponse(
|
||||
{"responseMimeType", "application/json"}
|
||||
}}
|
||||
};
|
||||
|
||||
// Add function calling tools if enabled
|
||||
if (function_calling_enabled_) {
|
||||
try {
|
||||
nlohmann::json tools = nlohmann::json::parse(BuildFunctionCallSchemas());
|
||||
request_body["tools"] = {{
|
||||
{"function_declarations", tools}
|
||||
}};
|
||||
} catch (const nlohmann::json::exception& e) {
|
||||
std::cerr << "⚠️ Failed to parse function schemas: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
httplib::Headers headers = {
|
||||
{"Content-Type", "application/json"},
|
||||
|
||||
@@ -37,12 +37,19 @@ class GeminiAIService : public AIService {
|
||||
|
||||
// Health check
|
||||
absl::Status CheckAvailability();
|
||||
|
||||
// Function calling support
|
||||
void EnableFunctionCalling(bool enable = true);
|
||||
std::vector<std::string> GetAvailableTools() const;
|
||||
|
||||
private:
|
||||
std::string BuildSystemInstruction();
|
||||
std::string BuildFunctionCallSchemas();
|
||||
absl::StatusOr<AgentResponse> ParseGeminiResponse(
|
||||
const std::string& response_body);
|
||||
|
||||
bool function_calling_enabled_ = true;
|
||||
|
||||
GeminiConfig config_;
|
||||
PromptBuilder prompt_builder_;
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
#include "cli/modern_cli.h"
|
||||
#include "cli/tui/command_palette.h"
|
||||
#include "cli/z3ed_ascii_logo.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace cli {
|
||||
@@ -761,9 +762,27 @@ void MainMenuComponent(ftxui::ScreenInteractive &screen) {
|
||||
rom_information = app_context.rom.title();
|
||||
}
|
||||
|
||||
// Create ASCII logo with styling
|
||||
auto logo = vbox({
|
||||
text(" ███████╗██████╗ ███████╗██████╗ ") | color(Color::Cyan1) | bold,
|
||||
text(" ╚══███╔╝╚════██╗██╔════╝██╔══██╗") | color(Color::Cyan1) | bold,
|
||||
text(" ███╔╝ █████╔╝█████╗ ██║ ██║") | color(Color::Cyan1) | bold,
|
||||
text(" ███╔╝ ╚═══██╗██╔══╝ ██║ ██║") | color(Color::Cyan1) | bold,
|
||||
text(" ███████╗██████╔╝███████╗██████╔╝") | color(Color::Cyan1) | bold,
|
||||
text(" ╚══════╝╚═════╝ ╚══════╝╚═════╝ ") | color(Color::Cyan1) | bold,
|
||||
text("") | center,
|
||||
hbox({
|
||||
text(" ▲ ") | color(Color::Yellow1) | bold,
|
||||
text("Zelda 3 Editor") | color(Color::White) | bold,
|
||||
}) | center,
|
||||
hbox({
|
||||
text(" ▲ ▲ ") | color(Color::Yellow1) | bold,
|
||||
text("AI-Powered CLI") | color(Color::GrayLight),
|
||||
}) | center,
|
||||
text(" ▲▲▲▲▲ ") | color(Color::Yellow1) | bold | center,
|
||||
});
|
||||
|
||||
auto title = border(hbox({
|
||||
text("z3ed") | bold | color(Color::Blue1),
|
||||
separator(),
|
||||
text("v0.3.2") | bold | color(Color::Green1),
|
||||
separator(),
|
||||
text(rom_information) | bold | color(Color::Red1),
|
||||
@@ -771,6 +790,8 @@ void MainMenuComponent(ftxui::ScreenInteractive &screen) {
|
||||
|
||||
auto renderer = Renderer(menu, [&] {
|
||||
return vbox({
|
||||
separator(),
|
||||
logo | center,
|
||||
separator(),
|
||||
title | center,
|
||||
separator(),
|
||||
|
||||
68
src/cli/z3ed_ascii_logo.h
Normal file
68
src/cli/z3ed_ascii_logo.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#ifndef YAZE_CLI_Z3ED_ASCII_LOGO_H_
|
||||
#define YAZE_CLI_Z3ED_ASCII_LOGO_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace yaze {
|
||||
namespace cli {
|
||||
|
||||
// ASCII art logo for z3ed CLI
|
||||
constexpr const char* kZ3edLogo = R"(
|
||||
███████╗██████╗ ███████╗██████╗
|
||||
╚══███╔╝╚════██╗██╔════╝██╔══██╗
|
||||
███╔╝ █████╔╝█████╗ ██║ ██║
|
||||
███╔╝ ╚═══██╗██╔══╝ ██║ ██║
|
||||
███████╗██████╔╝███████╗██████╔╝
|
||||
╚══════╝╚═════╝ ╚══════╝╚═════╝
|
||||
|
||||
▲ Zelda 3 Editor
|
||||
▲ ▲ AI-Powered CLI
|
||||
▲▲▲▲▲
|
||||
)";
|
||||
|
||||
constexpr const char* kZ3edLogoCompact = R"(
|
||||
╔════════════════════════════════╗
|
||||
║ ███████╗██████╗ ███████╗██████╗ ║
|
||||
║ ╚══███╔╝╚════██╗██╔════╝██╔══██╗ ║
|
||||
║ ███╔╝ █████╔╝█████╗ ██║ ██║ ║
|
||||
║ ███╔╝ ╚═══██╗██╔══╝ ██║ ██║ ║
|
||||
║ ███████╗██████╔╝███████╗██████╔╝ ║
|
||||
║ ╚══════╝╚═════╝ ╚══════╝╚═════╝ ║
|
||||
║ ▲ Zelda 3 Editor ║
|
||||
║ ▲ ▲ AI-Powered CLI ║
|
||||
║ ▲▲▲▲▲ ROM Hacking Tool ║
|
||||
╚════════════════════════════════╝
|
||||
)";
|
||||
|
||||
constexpr const char* kZ3edLogoMinimal = R"(
|
||||
╭──────────────────────╮
|
||||
│ Z3ED - Zelda 3 │
|
||||
│ ▲ Editor CLI │
|
||||
│ ▲ ▲ AI-Powered │
|
||||
│ ▲▲▲▲▲ │
|
||||
╰──────────────────────╯
|
||||
)";
|
||||
|
||||
// Get logo with color codes for terminal
|
||||
inline std::string GetColoredLogo() {
|
||||
return std::string("\033[1;36m") + // Cyan
|
||||
" ███████╗██████╗ ███████╗██████╗ \n"
|
||||
" ╚══███╔╝╚════██╗██╔════╝██╔══██╗\n"
|
||||
" ███╔╝ █████╔╝█████╗ ██║ ██║\n"
|
||||
" ███╔╝ ╚═══██╗██╔══╝ ██║ ██║\n"
|
||||
" ███████╗██████╔╝███████╗██████╔╝\n"
|
||||
" ╚══════╝╚═════╝ ╚══════╝╚═════╝ \n"
|
||||
"\033[1;33m" + // Yellow for triforce
|
||||
" \n"
|
||||
" ▲ " + "\033[1;37m" + "Zelda 3 Editor\n" + // White
|
||||
"\033[1;33m" +
|
||||
" ▲ ▲ " + "\033[0;37m" + "AI-Powered CLI\n" + // Gray
|
||||
"\033[1;33m" +
|
||||
" ▲▲▲▲▲ \n" +
|
||||
"\033[0m"; // Reset
|
||||
}
|
||||
|
||||
} // namespace cli
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_CLI_Z3ED_ASCII_LOGO_H_
|
||||
Reference in New Issue
Block a user