17#include "absl/strings/match.h"
18#include "absl/strings/str_format.h"
19#include "absl/time/clock.h"
20#include "absl/time/time.h"
31#include "imgui/misc/cpp/imgui_stdlib.h"
41#if defined(YAZE_WITH_JSON)
42#include "nlohmann/json.hpp"
84 {
"Persona",
"Define persona and goals",
false},
85 {
"Tool Stack",
"Select the agent's tools",
false},
86 {
"Automation",
"Configure automation hooks",
false},
87 {
"Validation",
"Describe E2E validation",
false},
88 {
"E2E Checklist",
"Track readiness for end-to-end runs",
false}};
90 "Describe the persona, tone, and constraints for this agent.";
108 std::make_unique<AgentConfigurationPanel>(
110 panel_manager->RegisterEditorPanel(
112 panel_manager->RegisterEditorPanel(std::make_unique<AgentPromptEditorPanel>(
114 panel_manager->RegisterEditorPanel(std::make_unique<AgentBotProfilesPanel>(
116 panel_manager->RegisterEditorPanel(std::make_unique<AgentChatHistoryPanel>(
118 panel_manager->RegisterEditorPanel(
119 std::make_unique<AgentMetricsDashboardPanel>(
121 panel_manager->RegisterEditorPanel(std::make_unique<AgentBuilderPanel>(
123 panel_manager->RegisterEditorPanel(
124 std::make_unique<AgentChatPanel>(
agent_chat_.get()));
127 panel_manager->RegisterEditorPanel(
128 std::make_unique<AgentKnowledgeBasePanel>([
this]() {
132 ImGui::TextDisabled(
"Knowledge service not available");
134 "Build with Z3ED_AI=ON to enable the knowledge service.");
150 if (std::filesystem::exists(profiles_dir)) {
151 for (
const auto& entry :
152 std::filesystem::directory_iterator(profiles_dir)) {
153 if (entry.path().extension() ==
".json") {
154 std::ifstream file(entry.path());
155 if (file.is_open()) {
156 std::string json_content((std::istreambuf_iterator<char>(file)),
157 std::istreambuf_iterator<char>());
159 if (profile_or.ok()) {
166 return absl::OkStatus();
177 return absl::OkStatus();
184 return absl::OkStatus();
195 if (
const char* gemini_key = std::getenv(
"GEMINI_API_KEY")) {
207 if (
const char* openai_key = std::getenv(
"OPENAI_API_KEY")) {
221 agent_chat_->Initialize(toast_manager, proposal_drawer);
232 harness_telemetry_bridge_.SetAgentChat(
agent_chat_.get());
254 ImGuiIO& imgui_io = ImGui::GetIO();
269 ImGui::TextDisabled(
"(?)");
270 if (ImGui::IsItemHovered()) {
271 ImGui::BeginTooltip();
272 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
273 ImGui::TextUnformatted(desc);
274 ImGui::PopTextWrapPos();
282 float avail_width = ImGui::GetContentRegionAvail().x;
283 ImVec2 button_size(avail_width / 2 - 8, 46);
285 auto ProviderButton = [&](
const char* label,
const char* provider_id,
286 const ImVec4& color) {
288 ImVec4 base_color = selected ? color : theme.panel_bg_darker;
296 ProviderButton(
ICON_MD_CLOUD " Ollama",
"ollama", theme.provider_ollama);
298 theme.provider_gemini);
301 theme.provider_gemini);
304 theme.provider_openai);
314 ImGui::Text(
"Model:");
315 ImGui::SetNextItemWidth(-1);
316 static char model_buf[128] =
"qwen2.5-coder:7b";
320 if (ImGui::InputTextWithHint(
"##ollama_model",
321 "e.g., qwen2.5-coder:7b, llama3.2", model_buf,
322 sizeof(model_buf))) {
326 ImGui::Text(
"Host URL:");
327 ImGui::SetNextItemWidth(-1);
328 static char host_buf[256] =
"http://localhost:11434";
330 sizeof(host_buf) - 1);
331 if (ImGui::InputText(
"##ollama_host", host_buf,
sizeof(host_buf))) {
339 if (ImGui::Button(
ICON_MD_REFRESH " Load from Env (GEMINI_API_KEY)")) {
340 const char* gemini_key = std::getenv(
"GEMINI_API_KEY");
351 HelpMarker(
"Loads GEMINI_API_KEY from your environment");
354 ImGui::Text(
"Model:");
355 ImGui::SetNextItemWidth(-1);
356 static char model_buf[128] =
"gemini-2.5-flash";
360 if (ImGui::InputTextWithHint(
"##gemini_model",
"e.g., gemini-2.5-flash",
361 model_buf,
sizeof(model_buf))) {
365 ImGui::Text(
"API Key:");
366 ImGui::SetNextItemWidth(-1);
367 static char key_buf[256] =
"";
370 sizeof(key_buf) - 1);
372 if (ImGui::InputText(
"##gemini_key", key_buf,
sizeof(key_buf),
373 ImGuiInputTextFlags_Password)) {
377 ImGui::TextColored(theme.status_success,
384 if (ImGui::Button(
ICON_MD_REFRESH " Load from Env (OPENAI_API_KEY)")) {
385 const char* openai_key = std::getenv(
"OPENAI_API_KEY");
396 HelpMarker(
"Loads OPENAI_API_KEY from your environment");
399 ImGui::Text(
"Model:");
400 ImGui::SetNextItemWidth(-1);
401 static char openai_model_buf[128] =
"gpt-4o-mini";
404 sizeof(openai_model_buf) - 1);
406 if (ImGui::InputTextWithHint(
"##openai_model",
"e.g., gpt-4o-mini",
407 openai_model_buf,
sizeof(openai_model_buf))) {
411 ImGui::Text(
"API Key:");
412 ImGui::SetNextItemWidth(-1);
413 static char openai_key_buf[256] =
"";
416 sizeof(openai_key_buf) - 1);
418 if (ImGui::InputText(
"##openai_key", openai_key_buf,
sizeof(openai_key_buf),
419 ImGuiInputTextFlags_Password)) {
423 ImGui::TextColored(theme.status_success,
432 HelpMarker(
"Logs provider requests/responses to console");
443 "Maximum number of tool calls the agent can make while solving a single "
447 HelpMarker(
"Number of times to retry API calls on failure.");
451 theme.text_secondary_gray);
453 static char name_buf[128];
455 if (ImGui::InputText(
"Name", name_buf,
sizeof(name_buf))) {
459 static char desc_buf[256];
461 if (ImGui::InputTextMultiline(
"Description", desc_buf,
sizeof(desc_buf),
466 ImGui::Text(
"Tags (comma-separated)");
467 static char tags_buf[256];
469 std::string tags_str;
475 strncpy(tags_buf, tags_str.c_str(),
sizeof(tags_buf) - 1);
477 if (ImGui::InputText(
"##profile_tags", tags_buf,
sizeof(tags_buf))) {
479 std::string tags_str(tags_buf);
481 while ((pos = tags_str.find(
',')) != std::string::npos) {
482 std::string tag = tags_str.substr(0, pos);
483 tag.erase(0, tag.find_first_not_of(
" \t"));
484 tag.erase(tag.find_last_not_of(
" \t") + 1);
488 tags_str.erase(0, pos + 1);
490 tags_str.erase(0, tags_str.find_first_not_of(
" \t"));
491 tags_str.erase(tags_str.find_last_not_of(
" \t") + 1);
492 if (!tags_str.empty()) {
498 ImGui::PushStyleColor(ImGuiCol_Button, theme.status_success);
499 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, theme.status_success);
500 if (ImGui::Button(
ICON_MD_CHECK " Apply & Save Configuration",
524 ImGui::PopStyleColor(2);
533 if (ImGui::BeginChild(
"ChatStatusCard", ImVec2(0, 140),
true)) {
541 if (!chat_active && ImGui::SmallButton(
"Open")) {
546 ImGui::Text(
"Provider:");
557 if (ImGui::BeginChild(
"RomStatusCard", ImVec2(0, 110),
true)) {
562 ImGui::TextDisabled(
"Tools: Ready");
564 ImGui::TextColored(theme.status_warning,
ICON_MD_WARNING " Not Loaded");
565 ImGui::TextDisabled(
"Load a ROM to enable tool calls.");
572 if (ImGui::BeginChild(
"QuickTipsCard", ImVec2(0, 130),
true)) {
575 ImGui::BulletText(
"Ctrl+H: Toggle chat popup");
576 ImGui::BulletText(
"Ctrl+P: View proposals");
577 ImGui::BulletText(
"Edit prompts in Prompt Editor");
578 ImGui::BulletText(
"Create and save custom bots");
586 ImGui::TextDisabled(
"View detailed metrics in the Metrics tab");
595 ImGui::Text(
"File:");
596 ImGui::SetNextItemWidth(-45);
598 const char* options[] = {
"system_prompt.txt",
"system_prompt_v2.txt",
599 "system_prompt_v3.txt"};
600 for (
const char* option : options) {
602 if (ImGui::Selectable(option, selected)) {
614 if (ImGui::IsItemHovered()) {
615 ImGui::SetTooltip(
"Reload from disk");
621 if (content_result.ok()) {
631 std::string placeholder = absl::StrFormat(
632 "# System prompt file not found: %s\n"
634 "# Ensure the file exists in assets/agent/%s\n",
644 ImVec2 editor_size(ImGui::GetContentRegionAvail().x,
645 ImGui::GetContentRegionAvail().y - 60);
649 if (ImGui::Button(
ICON_MD_SAVE " Save Prompt to Profile", ImVec2(-1, 0))) {
660 "Edit the system prompt that guides the agent's behavior. Changes are "
661 "stored on the active bot profile.");
670 ImGui::BeginChild(
"CurrentProfile", ImVec2(0, 150),
true);
678 ImGui::TextWrapped(
"Description: %s",
686 if (ImGui::Button(
ICON_MD_ADD " Create New Profile", ImVec2(-1, 0))) {
688 new_profile.
name =
"New Profile";
702 ImGui::BeginChild(
"ProfilesList", ImVec2(0, 0),
true);
705 "No saved profiles. Create and save a profile to see it here.");
709 ImGui::PushID(
static_cast<int>(i));
712 ImVec2 button_size(ImGui::GetContentRegionAvail().x - 80, 0);
713 ImVec4 button_color =
714 is_current ? theme.accent_color : theme.panel_bg_darker;
720 absl::StrFormat(
"Loaded profile: %s", profile.name),
730 ImGui::PushStyleColor(ImGuiCol_Button, theme.status_warning);
735 absl::StrFormat(
"Deleted profile: %s", profile.name),
743 ImGui::PopStyleColor();
745 ImGui::TextDisabled(
" %s | %s", profile.provider.c_str(),
746 profile.description.empty()
748 : profile.description.c_str());
780 ImGui::BeginChild(
"HistoryList", ImVec2(0, 0),
true);
783 "No chat history. Start a conversation in the chat window.");
788 from_user ? theme.user_message_color : theme.agent_message_color;
790 ImGui::PushStyleColor(ImGuiCol_Text, color);
791 ImGui::Text(
"%s:", from_user ?
"User" :
"Agent");
792 ImGui::PopStyleColor();
795 ImGui::TextDisabled(
"%s", absl::FormatTime(
"%H:%M:%S", msg.timestamp,
796 absl::LocalTimeZone())
799 ImGui::TextWrapped(
"%s", msg.message.c_str());
814 auto metrics =
agent_chat_->GetAgentService()->GetMetrics();
815 if (ImGui::BeginTable(
"MetricsTable", 2,
816 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
817 ImGui::TableSetupColumn(
"Metric", ImGuiTableColumnFlags_WidthFixed,
819 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
820 ImGui::TableHeadersRow();
822 auto Row = [](
const char* label,
const std::string& value) {
823 ImGui::TableNextRow();
824 ImGui::TableSetColumnIndex(0);
825 ImGui::Text(
"%s", label);
826 ImGui::TableSetColumnIndex(1);
827 ImGui::TextDisabled(
"%s", value.c_str());
830 Row(
"Total Messages",
831 absl::StrFormat(
"%d user / %d agent", metrics.total_user_messages,
832 metrics.total_agent_messages));
833 Row(
"Tool Calls", absl::StrFormat(
"%d", metrics.total_tool_calls));
834 Row(
"Commands", absl::StrFormat(
"%d", metrics.total_commands));
835 Row(
"Proposals", absl::StrFormat(
"%d", metrics.total_proposals));
836 Row(
"Average Latency (s)",
837 absl::StrFormat(
"%.2f", metrics.average_latency_seconds));
839 absl::StrFormat(
"%.2f", metrics.total_elapsed_seconds));
844 ImGui::TextDisabled(
"Initialize the chat system to see metrics.");
855 "Customize the tile reference file that AI uses for tile placement. "
856 "Organize tiles by category and provide hex IDs with descriptions.");
873 if (ImGui::Button(
ICON_MD_SAVE " Save", ImVec2(100, 0))) {
876 " Save to project directory (coming soon)",
885 if (ImGui::IsItemHovered()) {
886 ImGui::SetTooltip(
"Reload from disk");
894 std::string default_tiles =
895 "# Common Tile16 Reference\n"
896 "# Format: 0xHEX = Description\n\n"
898 "0x020 = Grass (standard)\n\n"
900 "0x02E = Tree (oak)\n"
903 "0x14C = Water (top edge)\n"
904 "0x14D = Water (middle)\n";
914 ImVec2 editor_size(ImGui::GetContentRegionAvail().x,
915 ImGui::GetContentRegionAvail().y);
927 "Create a custom system prompt from scratch or start from a template.");
930 ImGui::Text(
"Prompt Name:");
931 ImGui::SetNextItemWidth(-1);
932 ImGui::InputTextWithHint(
"##new_prompt_name",
"e.g., custom_prompt.txt",
936 ImGui::Text(
"Start from template:");
938 auto LoadTemplate = [&](
const char* path,
const char* label) {
939 if (ImGui::Button(label, ImVec2(-1, 0))) {
951 LoadTemplate(
"agent/system_prompt_v2.txt",
953 LoadTemplate(
"agent/system_prompt_v3.txt",
958 std::string blank_template =
959 "# Custom System Prompt\n\n"
960 "You are an AI assistant for ROM hacking.\n\n"
962 "- Help users understand ROM data\n"
963 "- Provide accurate information\n"
964 "- Use tools when needed\n\n"
966 "1. Always provide text_response after tool calls\n"
967 "2. Be helpful and accurate\n"
968 "3. Explain your reasoning\n";
980 ImGui::PushStyleColor(ImGuiCol_Button, theme.status_success);
981 if (ImGui::Button(
ICON_MD_SAVE " Save New Prompt", ImVec2(-1, 40))) {
984 if (!absl::EndsWith(filename,
".txt")) {
989 absl::StrFormat(
ICON_MD_SAVE " Prompt saved as %s", filename),
998 ImGui::PopStyleColor();
1002 "Note: New prompts are saved to your project. Use the Prompt Editor to "
1003 "edit existing prompts.");
1009 theme.accent_color);
1012 ImGui::TextDisabled(
"Chat system not initialized.");
1016 ImGui::BeginChild(
"AgentBuilderPanel", ImVec2(0, 0),
false);
1017 ImGui::Columns(2,
nullptr,
false);
1018 ImGui::TextColored(theme.accent_color,
"Stages");
1023 ImGui::PushID(
static_cast<int>(i));
1025 if (ImGui::Selectable(stage.name.c_str(), selected)) {
1028 ImGui::SameLine(ImGui::GetContentRegionAvail().x - 24.0f);
1029 ImGui::Checkbox(
"##stage_done", &stage.completed);
1033 ImGui::NextColumn();
1034 ImGui::TextColored(theme.text_info,
"Stage Details");
1040 int completed_stages = 0;
1042 if (stage.completed) {
1047 switch (stage_index) {
1049 static std::string new_goal;
1050 ImGui::Text(
"Persona + Goals");
1051 ImGui::InputTextMultiline(
"##persona_notes",
1054 ImGui::TextDisabled(
"Add Goal");
1055 ImGui::InputTextWithHint(
"##goal_input",
"e.g. Document dungeon plan",
1058 if (ImGui::Button(
ICON_MD_ADD) && !new_goal.empty()) {
1065 ImGui::PushID(
static_cast<int>(i));
1076 ImGui::Text(
"Tool Stack");
1077 auto tool_checkbox = [&](
const char* label,
bool* value) {
1078 ImGui::Checkbox(label, value);
1091 ImGui::Text(
"Automation");
1094 ImGui::Checkbox(
"Auto-focus proposal drawer",
1097 "Enable these options to push harness dashboards/test plans when "
1098 "executing plans.");
1102 ImGui::Text(
"Validation Criteria");
1103 ImGui::InputTextMultiline(
"##validation_notes",
1109 ImGui::Text(
"E2E Checklist");
1113 :
static_cast<float>(completed_stages) /
1115 ImGui::ProgressBar(progress, ImVec2(-1, 0),
1116 absl::StrFormat(
"%d/%zu complete", completed_stages,
1119 ImGui::Checkbox(
"Ready for automation handoff",
1121 ImGui::TextDisabled(
"Auto-sync ROM: %s",
1123 ImGui::TextDisabled(
"Auto-focus proposals: %s",
1132 float completion_ratio =
1135 :
static_cast<float>(completed_stages) /
1137 ImGui::TextDisabled(
"Overall Progress");
1138 ImGui::ProgressBar(completion_ratio, ImVec2(-1, 0));
1139 ImGui::TextDisabled(
"E2E Ready: %s",
1153#ifdef YAZE_WITH_GRPC
1156 service->SetToolPreferences(prefs);
1158 auto agent_cfg = service->GetConfig();
1163 service->SetConfig(agent_cfg);
1175 ImGui::InputTextWithHint(
"##blueprint_path",
"Path to blueprint...",
1177 std::filesystem::path blueprint_path =
1179 ? (std::filesystem::temp_directory_path() /
"agent_builder.json")
1212 const std::filesystem::path& path) {
1213#if defined(YAZE_WITH_JSON)
1214 nlohmann::json json;
1231 json[
"stages"] = nlohmann::json::array();
1233 json[
"stages"].push_back({{
"name", stage.name},
1234 {
"summary", stage.summary},
1235 {
"completed", stage.completed}});
1239 std::filesystem::create_directories(path.parent_path(), ec);
1240 std::ofstream file(path);
1241 if (!file.is_open()) {
1242 return absl::InternalError(
1243 absl::StrFormat(
"Failed to open blueprint: %s", path.string()));
1245 file << json.dump(2);
1247 return absl::OkStatus();
1250 return absl::UnimplementedError(
"Blueprint export requires JSON support");
1255 const std::filesystem::path& path) {
1256#if defined(YAZE_WITH_JSON)
1257 std::ifstream file(path);
1258 if (!file.is_open()) {
1259 return absl::NotFoundError(
1260 absl::StrFormat(
"Blueprint not found: %s", path.string()));
1263 nlohmann::json json;
1268 if (json.contains(
"goals") && json[
"goals"].is_array()) {
1269 for (
const auto& goal : json[
"goals"]) {
1270 if (goal.is_string()) {
1275 if (json.contains(
"tools") && json[
"tools"].is_object()) {
1276 auto tools = json[
"tools"];
1289 json.value(
"auto_focus_proposals",
true);
1291 if (json.contains(
"stages") && json[
"stages"].is_array()) {
1293 for (
const auto& stage : json[
"stages"]) {
1295 builder_stage.
name = stage.value(
"name", std::string{});
1296 builder_stage.
summary = stage.value(
"summary", std::string{});
1297 builder_stage.
completed = stage.value(
"completed",
false);
1302 return absl::OkStatus();
1305 return absl::UnimplementedError(
"Blueprint import requires JSON support");
1310#if defined(YAZE_WITH_JSON)
1312 if (!dir_status.ok())
1315 std::filesystem::path profile_path =
1317 std::ofstream file(profile_path);
1318 if (!file.is_open()) {
1319 return absl::InternalError(
"Failed to open profile file for writing");
1326 return absl::UnimplementedError(
1327 "JSON support required for profile management");
1332#if defined(YAZE_WITH_JSON)
1333 std::filesystem::path profile_path =
1335 if (!std::filesystem::exists(profile_path)) {
1336 return absl::NotFoundError(absl::StrFormat(
"Profile '%s' not found", name));
1339 std::ifstream file(profile_path);
1340 if (!file.is_open()) {
1341 return absl::InternalError(
"Failed to open profile file");
1344 std::string json_content((std::istreambuf_iterator<char>(file)),
1345 std::istreambuf_iterator<char>());
1348 if (!profile_or.ok()) {
1349 return profile_or.status();
1368 return absl::OkStatus();
1370 return absl::UnimplementedError(
1371 "JSON support required for profile management");
1376 std::filesystem::path profile_path =
1378 if (!std::filesystem::exists(profile_path)) {
1379 return absl::NotFoundError(absl::StrFormat(
"Profile '%s' not found", name));
1382 std::filesystem::remove(profile_path);
1410 const std::filesystem::path& path) {
1411#if defined(YAZE_WITH_JSON)
1416 std::ofstream file(path);
1417 if (!file.is_open()) {
1418 return absl::InternalError(
"Failed to open file for export");
1421 return absl::OkStatus();
1425 return absl::UnimplementedError(
"JSON support required");
1430#if defined(YAZE_WITH_JSON)
1431 if (!std::filesystem::exists(path)) {
1432 return absl::NotFoundError(
"Import file not found");
1435 std::ifstream file(path);
1436 if (!file.is_open()) {
1437 return absl::InternalError(
"Failed to open import file");
1440 std::string json_content((std::istreambuf_iterator<char>(file)),
1441 std::istreambuf_iterator<char>());
1444 if (!profile_or.ok()) {
1445 return profile_or.status();
1451 return absl::UnimplementedError(
"JSON support required");
1457 if (agent_dir.ok()) {
1458 return *agent_dir /
"profiles";
1462 if (docs_dir.ok()) {
1463 return *docs_dir /
"profiles";
1466 if (temp_dir.ok()) {
1467 return *temp_dir /
"agent" /
"profiles";
1469 return std::filesystem::current_path() /
"agent" /
"profiles";
1475 std::filesystem::create_directories(dir, ec);
1477 return absl::InternalError(absl::StrFormat(
1478 "Failed to create profiles directory: %s", ec.message()));
1480 return absl::OkStatus();
1484#if defined(YAZE_WITH_JSON)
1485 nlohmann::json json;
1486 json[
"name"] = profile.
name;
1488 json[
"provider"] = profile.
provider;
1489 json[
"model"] = profile.
model;
1494 json[
"verbose"] = profile.
verbose;
1499 json[
"top_p"] = profile.
top_p;
1502 json[
"tags"] = profile.
tags;
1503 json[
"created_at"] = absl::FormatTime(absl::RFC3339_full, profile.
created_at,
1504 absl::UTCTimeZone());
1505 json[
"modified_at"] = absl::FormatTime(
1506 absl::RFC3339_full, profile.
modified_at, absl::UTCTimeZone());
1508 return json.dump(2);
1515 const std::string& json_str)
const {
1516#if defined(YAZE_WITH_JSON)
1518 nlohmann::json json = nlohmann::json::parse(json_str);
1521 profile.
name = json.value(
"name",
"Unnamed Profile");
1522 profile.
description = json.value(
"description",
"");
1523 profile.
provider = json.value(
"provider",
"mock");
1524 profile.
model = json.value(
"model",
"");
1525 profile.
ollama_host = json.value(
"ollama_host",
"http://localhost:11434");
1529 profile.
verbose = json.value(
"verbose",
false);
1533 profile.
temperature = json.value(
"temperature", 0.25f);
1534 profile.
top_p = json.value(
"top_p", 0.95f);
1538 if (json.contains(
"tags") && json[
"tags"].is_array()) {
1539 for (
const auto& tag : json[
"tags"]) {
1540 profile.
tags.push_back(tag.get<std::string>());
1544 if (json.contains(
"created_at")) {
1546 if (absl::ParseTime(absl::RFC3339_full,
1547 json[
"created_at"].get<std::string>(), &created,
1553 if (json.contains(
"modified_at")) {
1554 absl::Time modified;
1555 if (absl::ParseTime(absl::RFC3339_full,
1556 json[
"modified_at"].get<std::string>(), &modified,
1563 }
catch (
const std::exception& e) {
1564 return absl::InternalError(
1565 absl::StrFormat(
"Failed to parse profile JSON: %s", e.what()));
1568 return absl::UnimplementedError(
"JSON support required");
1591 auto status = service->ConfigureProvider(provider_config);
1596 auto agent_cfg = service->GetConfig();
1599 agent_cfg.verbose = config.
verbose;
1601 service->SetConfig(agent_cfg);
1632 if (!session_or.ok())
1633 return session_or.status();
1647 absl::StrFormat(
"Hosting local session: %s", session_name),
1653#ifdef YAZE_WITH_GRPC
1655 if (!network_coordinator_) {
1656 return absl::FailedPreconditionError(
1657 "Network coordinator not initialized. Connect to a server first.");
1660 const char* username = std::getenv(
"USER");
1662 username = std::getenv(
"USERNAME");
1665 username =
"unknown";
1668 auto session_or = network_coordinator_->HostSession(session_name, username);
1669 if (!session_or.ok())
1670 return session_or.status();
1684 absl::StrFormat(
"Hosting network session: %s", session_name),
1692 return absl::InvalidArgumentError(
"Unsupported collaboration mode");
1701 if (!session_or.ok())
1702 return session_or.status();
1716 absl::StrFormat(
"Joined local session: %s", session_code),
1723#ifdef YAZE_WITH_GRPC
1725 if (!network_coordinator_) {
1726 return absl::FailedPreconditionError(
1727 "Network coordinator not initialized. Connect to a server first.");
1730 const char* username = std::getenv(
"USER");
1732 username = std::getenv(
"USERNAME");
1735 username =
"unknown";
1738 auto session_or = network_coordinator_->JoinSession(session_code, username);
1739 if (!session_or.ok())
1740 return session_or.status();
1754 absl::StrFormat(
"Joined network session: %s", session_code),
1762 return absl::InvalidArgumentError(
"Unsupported collaboration mode");
1767 return absl::FailedPreconditionError(
"Not in a session");
1775#ifdef YAZE_WITH_GRPC
1777 if (network_coordinator_) {
1778 auto status = network_coordinator_->LeaveSession();
1794 return absl::OkStatus();
1799 return absl::FailedPreconditionError(
"Not in a session");
1804 if (!session_or.ok())
1805 return session_or.status();
1824#ifdef YAZE_WITH_GRPC
1825 using yaze::test::CaptureActiveWindow;
1826 using yaze::test::CaptureHarnessScreenshot;
1827 using yaze::test::CaptureWindowByName;
1829 absl::StatusOr<yaze::test::ScreenshotArtifact> result;
1830 switch (config.
mode) {
1832 result = CaptureHarnessScreenshot(
"");
1835 result = CaptureActiveWindow(
"");
1837 result = CaptureHarnessScreenshot(
"");
1844 result = CaptureActiveWindow(
"");
1847 result = CaptureHarnessScreenshot(
"");
1854 return result.status();
1856 *output_path = result->file_path;
1857 return absl::OkStatus();
1861 return absl::UnimplementedError(
"Screenshot capture requires YAZE_WITH_GRPC");
1866 const std::string& prompt) {
1867#ifdef YAZE_WITH_GRPC
1869 ? std::getenv(
"GEMINI_API_KEY")
1871 if (!api_key || std::strlen(api_key) == 0) {
1872 return absl::FailedPreconditionError(
1873 "Gemini API key not configured (set GEMINI_API_KEY)");
1885 if (!response.ok()) {
1886 return response.status();
1892 auto history = service->GetHistory();
1895 agent_msg.
message = response->text_response;
1897 history.push_back(agent_msg);
1898 service->ReplaceHistory(history);
1906 return absl::OkStatus();
1910 return absl::UnimplementedError(
"Gemini integration requires YAZE_WITH_GRPC");
1914#ifdef YAZE_WITH_GRPC
1915absl::Status AgentEditor::ConnectToServer(
const std::string& server_url) {
1917 network_coordinator_ =
1918 std::make_unique<NetworkCollaborationCoordinator>(server_url);
1922 absl::StrFormat(
"Connected to server: %s", server_url),
1926 return absl::OkStatus();
1927 }
catch (
const std::exception& e) {
1928 return absl::InternalError(
1929 absl::StrFormat(
"Failed to connect to server: %s", e.what()));
1933void AgentEditor::DisconnectFromServer() {
1937 network_coordinator_.reset();
1944bool AgentEditor::IsConnectedToServer()
const {
1945 return network_coordinator_ && network_coordinator_->IsConnected();
1959 return std::nullopt;
static absl::StatusOr< std::string > LoadTextFile(const std::string &relative_path)
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
absl::StatusOr< AgentResponse > GenerateMultimodalResponse(const std::string &, const std::string &)
std::string current_session_id_
void SetCurrentProfile(const BotProfile &profile)
void ApplyConfig(const AgentConfig &config)
void InitializeWithDependencies(ToastManager *toast_manager, ProposalDrawer *proposal_drawer, Rom *rom)
absl::Status SaveBuilderBlueprint(const std::filesystem::path &path)
void DrawAdvancedMetricsPanel()
absl::StatusOr< SessionInfo > JoinSession(const std::string &session_code, CollaborationMode mode=CollaborationMode::kLocal)
void SetRomContext(Rom *rom)
void SetChatActive(bool active)
void SetupAutomationCallbacks()
KnowledgePanelCallback knowledge_panel_callback_
absl::StatusOr< BotProfile > JsonToProfile(const std::string &json) const
absl::StatusOr< SessionInfo > RefreshSession()
absl::Status ImportProfile(const std::filesystem::path &path)
bool IsChatActive() const
void SetupMultimodalCallbacks()
bool prompt_editor_initialized_
void Initialize() override
ProposalDrawer * proposal_drawer_
std::vector< cli::agent::ChatMessage > cached_history_
AgentBuilderState builder_state_
AgentConfig current_config_
absl::Status Save() override
bool common_tiles_initialized_
std::string current_session_name_
CollaborationMode GetCurrentMode() const
void DrawPromptEditorPanel()
absl::Status SendToGemini(const std::filesystem::path &image_path, const std::string &prompt)
absl::Status EnsureProfilesDirectory()
absl::Status LoadBuilderBlueprint(const std::filesystem::path &path)
bool history_needs_refresh_
absl::Status ExportProfile(const BotProfile &profile, const std::filesystem::path &path)
void DrawNewPromptCreator()
CollaborationMode current_mode_
absl::Status SaveBotProfile(const BotProfile &profile)
std::string active_prompt_file_
absl::Status DeleteBotProfile(const std::string &name)
std::filesystem::path GetProfilesDirectory() const
ToastManager * toast_manager_
AgentConfig GetCurrentConfig() const
std::unique_ptr< TextEditor > common_tiles_editor_
absl::StatusOr< SessionInfo > HostSession(const std::string &session_name, CollaborationMode mode=CollaborationMode::kLocal)
void DrawCommonTilesEditor()
char new_prompt_name_[128]
std::string ProfileToJson(const BotProfile &profile) const
absl::Status LeaveSession()
std::unique_ptr< TextEditor > prompt_editor_
std::unique_ptr< AgentCollaborationCoordinator > local_coordinator_
absl::Status CaptureSnapshot(std::filesystem::path *output_path, const CaptureConfig &config)
absl::Status Load() override
BotProfile current_profile_
absl::Status LoadBotProfile(const std::string &name)
std::vector< BotProfile > GetAllProfiles() const
void DrawChatHistoryViewer()
std::vector< std::string > current_participants_
void DrawBotProfilesPanel()
std::unique_ptr< AgentChat > agent_chat_
absl::Status Update() override
void DrawConfigurationPanel()
std::vector< BotProfile > loaded_profiles_
std::optional< SessionInfo > GetCurrentSession() const
void DrawAgentBuilderPanel()
EditorDependencies dependencies_
void RegisterEditorPanel(std::unique_ptr< EditorPanel > panel)
Register an EditorPanel instance for central drawing.
ImGui drawer for displaying and managing agent proposals.
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f)
static TestManager & Get()
#define ICON_MD_FOLDER_OPEN
#define ICON_MD_AUTO_AWESOME
#define ICON_MD_TIPS_AND_UPDATES
#define ICON_MD_AUTO_FIX_HIGH
#define ICON_MD_FILE_COPY
#define ICON_MD_CHECK_CIRCLE
#define ICON_MD_DELETE_FOREVER
#define ICON_MD_ANALYTICS
#define ICON_MD_SMART_TOY
void RenderStatusIndicator(const char *label, bool active)
bool StyledButton(const char *label, const ImVec4 &color, const ImVec2 &size)
const AgentUITheme & GetTheme()
void RenderSectionHeader(const char *icon, const char *label, const ImVec4 &color)
void RenderProviderBadge(const char *provider)
void HelpMarker(const char *desc)
static const LanguageDefinition & CPlusPlus()
std::string gemini_api_key
std::string openai_api_key
struct yaze::editor::AgentEditor::AgentBuilderState::ToolPlan tools
std::string persona_notes
std::vector< std::string > goals
std::vector< Stage > stages
bool auto_focus_proposals
std::string blueprint_path
std::string gemini_api_key
std::string openai_api_key
std::vector< std::string > tags
std::string openai_api_key
std::string gemini_api_key
std::string system_prompt
std::string specific_window_name
std::vector< std::string > participants
PanelManager * panel_manager