refactor: Remove app_main.cc as the application entry point

- Deleted app_main.cc to streamline the project structure, as it is no longer needed.
- Updated CMakeLists.txt to remove references to the deleted app_main.cc file, ensuring a clean build configuration.
This commit is contained in:
scawful
2025-10-05 14:54:19 -04:00
parent c6ba93fd33
commit c3f03472c1
5 changed files with 665 additions and 697 deletions

View File

@@ -483,11 +483,6 @@ if (YAZE_BUILD_LIB)
cli/service/gui/gui_automation_client.cc cli/service/gui/gui_automation_client.cc
) )
# Application main entry point (uses controller and full dependencies)
set(YAZE_APP_MAIN_SOURCES
./app_main.cc
)
if(YAZE_USE_MODULAR_BUILD) if(YAZE_USE_MODULAR_BUILD)
# Aggregate modular libraries into an interface target for backward compatibility # Aggregate modular libraries into an interface target for backward compatibility
if(NOT TARGET yaze_core) if(NOT TARGET yaze_core)

View File

@@ -810,7 +810,7 @@ void AgentChatWidget::Draw() {
// Connection status bar at top (taller for better visibility) // Connection status bar at top (taller for better visibility)
ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImVec2 bar_start = ImGui::GetCursorScreenPos(); ImVec2 bar_start = ImGui::GetCursorScreenPos();
ImVec2 bar_size(ImGui::GetContentRegionAvail().x, 90); // Increased from 55 ImVec2 bar_size(ImGui::GetContentRegionAvail().x, 60); // Increased from 55
// Gradient background // Gradient background
ImU32 color_top = ImGui::GetColorU32(ImVec4(0.18f, 0.22f, 0.28f, 1.0f)); ImU32 color_top = ImGui::GetColorU32(ImVec4(0.18f, 0.22f, 0.28f, 1.0f));
@@ -1046,8 +1046,17 @@ void AgentChatWidget::Draw() {
ImVec2(4, 3)); // Compact padding ImVec2(4, 3)); // Compact padding
// Removed RenderAgentConfigPanel - duplicates connection header // Removed RenderAgentConfigPanel - duplicates connection header
if (ImGui::BeginTable("##commands_and_multimodal", 2, ImGuiTableFlags_BordersInnerV)) {
ImGui::TableSetupColumn("Commands", ImGuiTableColumnFlags_WidthFixed, 180);
ImGui::TableSetupColumn("Multimodal", ImGuiTableColumnFlags_WidthFixed, ImGui::GetContentRegionAvail().x - 180);
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
RenderZ3EDCommandPanel(); RenderZ3EDCommandPanel();
ImGui::TableSetColumnIndex(1);
RenderMultimodalPanel(); RenderMultimodalPanel();
ImGui::EndTable();
}
RenderCollaborationPanel(); RenderCollaborationPanel();
RenderRomSyncPanel(); RenderRomSyncPanel();
RenderProposalManagerPanel(); RenderProposalManagerPanel();
@@ -1068,6 +1077,10 @@ void AgentChatWidget::Draw() {
void AgentChatWidget::RenderCollaborationPanel() { void AgentChatWidget::RenderCollaborationPanel() {
ImGui::PushID("CollabPanel"); ImGui::PushID("CollabPanel");
// Tighter style for more content
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 3));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(3, 2));
// Update reactive status color // Update reactive status color
const bool connected = collaboration_state_.active; const bool connected = collaboration_state_.active;
collaboration_status_color_ = connected ? ImVec4(0.133f, 0.545f, 0.133f, 1.0f) collaboration_status_color_ = connected ? ImVec4(0.133f, 0.545f, 0.133f, 1.0f)
@@ -1075,13 +1088,10 @@ void AgentChatWidget::RenderCollaborationPanel() {
// Always visible (no collapsing header) // Always visible (no collapsing header)
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.12f, 0.14f, 0.18f, 0.95f)); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.12f, 0.14f, 0.18f, 0.95f));
ImGui::BeginChild("CollabPanel", ImVec2(0, 200), true); ImGui::BeginChild("CollabPanel", ImVec2(0, 140), true); // reduced height
ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), ICON_MD_PEOPLE " Collaboration"); ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), ICON_MD_PEOPLE " Collaboration");
ImGui::Separator(); ImGui::SameLine();
ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), ICON_MD_SETTINGS_ETHERNET " Mode:");
// Mode selector (compact inline)
ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f),
ICON_MD_SETTINGS_ETHERNET " Mode:");
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton(ICON_MD_FOLDER " Local##collab_mode_local", ImGui::RadioButton(ICON_MD_FOLDER " Local##collab_mode_local",
reinterpret_cast<int*>(&collaboration_state_.mode), reinterpret_cast<int*>(&collaboration_state_.mode),
@@ -1091,13 +1101,11 @@ void AgentChatWidget::RenderCollaborationPanel() {
reinterpret_cast<int*>(&collaboration_state_.mode), reinterpret_cast<int*>(&collaboration_state_.mode),
static_cast<int>(CollaborationMode::kNetwork)); static_cast<int>(CollaborationMode::kNetwork));
ImGui::Spacing();
// Main content in table layout (fixed size to prevent auto-resize) // Main content in table layout (fixed size to prevent auto-resize)
if (ImGui::BeginTable("Collab_MainTable", 2, ImGuiTableFlags_BordersInnerV)) { if (ImGui::BeginTable("Collab_MainTable", 2, ImGuiTableFlags_BordersInnerV)) {
ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 180); ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 150);
ImGui::TableSetupColumn("Controls", ImGuiTableColumnFlags_WidthFixed, ImGui::TableSetupColumn("Controls", ImGuiTableColumnFlags_WidthFixed,
ImGui::GetContentRegionAvail().x - 180); ImGui::GetContentRegionAvail().x - 150);
ImGui::TableNextRow(); ImGui::TableNextRow();
// LEFT COLUMN: Session Details // LEFT COLUMN: Session Details
@@ -1106,10 +1114,9 @@ void AgentChatWidget::RenderCollaborationPanel() {
ImGui::PushID("StatusColumn"); ImGui::PushID("StatusColumn");
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.15f, 0.2f, 0.18f, 0.4f)); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.15f, 0.2f, 0.18f, 0.4f));
ImGui::BeginChild("Collab_SessionDetails", ImVec2(0, 80), true); ImGui::BeginChild("Collab_SessionDetails", ImVec2(0, 60), true); // reduced height
ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f),
ICON_MD_INFO " Session Status:"); ICON_MD_INFO " Session:");
ImGui::Spacing();
if (connected) { if (connected) {
ImGui::TextColored(collaboration_status_color_, ImGui::TextColored(collaboration_status_color_,
ICON_MD_CHECK_CIRCLE " Connected"); ICON_MD_CHECK_CIRCLE " Connected");
@@ -1118,72 +1125,55 @@ void AgentChatWidget::RenderCollaborationPanel() {
} }
if (collaboration_state_.mode == CollaborationMode::kNetwork) { if (collaboration_state_.mode == CollaborationMode::kNetwork) {
ImGui::Spacing();
ImGui::TextColored(ImVec4(0.196f, 0.6f, 0.8f, 1.0f), ImGui::TextColored(ImVec4(0.196f, 0.6f, 0.8f, 1.0f),
ICON_MD_CLOUD " Server:"); ICON_MD_CLOUD " Server:");
ImGui::TextWrapped("%s", collaboration_state_.server_url.c_str()); ImGui::TextUnformatted(collaboration_state_.server_url.c_str());
} }
if (!collaboration_state_.session_name.empty()) { if (!collaboration_state_.session_name.empty()) {
ImGui::Spacing();
ImGui::TextColored(collaboration_status_color_, ImGui::TextColored(collaboration_status_color_,
ICON_MD_LABEL " Session:"); ICON_MD_LABEL " %s", collaboration_state_.session_name.c_str());
ImGui::TextWrapped("%s", collaboration_state_.session_name.c_str());
} }
if (!collaboration_state_.session_id.empty()) { if (!collaboration_state_.session_id.empty()) {
ImGui::Spacing();
ImGui::TextColored(collaboration_status_color_, ImGui::TextColored(collaboration_status_color_,
ICON_MD_KEY " Session Code:"); ICON_MD_KEY " %s", collaboration_state_.session_id.c_str());
ImGui::TextWrapped("%s", collaboration_state_.session_id.c_str()); ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.4f, 0.4f, 0.6f, 0.6f)); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.4f, 0.4f, 0.6f, 0.6f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
ImVec4(0.416f, 0.353f, 0.804f, 1.0f)); ImVec4(0.416f, 0.353f, 0.804f, 1.0f));
if (ImGui::Button(ICON_MD_CONTENT_COPY " Copy##copy_session_id")) { if (ImGui::SmallButton(ICON_MD_CONTENT_COPY "##copy_session_id")) {
ImGui::SetClipboardText(collaboration_state_.session_id.c_str()); ImGui::SetClipboardText(collaboration_state_.session_id.c_str());
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show("Session code copied!", ToastType::kSuccess, toast_manager_->Show("Session code copied!", ToastType::kSuccess, 2.0f);
2.0f);
} }
} }
ImGui::PopStyleColor(2); ImGui::PopStyleColor(2);
} }
if (collaboration_state_.last_synced != absl::InfinitePast()) { if (collaboration_state_.last_synced != absl::InfinitePast()) {
ImGui::Spacing();
ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
ICON_MD_ACCESS_TIME " Last sync:"); ICON_MD_ACCESS_TIME " %s",
ImGui::SameLine();
ImGui::TextColored(
ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "%s",
absl::FormatTime("%H:%M:%S", collaboration_state_.last_synced, absl::FormatTime("%H:%M:%S", collaboration_state_.last_synced,
absl::LocalTimeZone()) absl::LocalTimeZone()).c_str());
.c_str());
} }
ImGui::EndChild(); ImGui::EndChild();
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::Spacing();
// Participants list below session details // Participants list below session details
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.12f, 0.16f, 0.14f, 0.4f)); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.12f, 0.16f, 0.14f, 0.4f));
ImGui::BeginChild("Collab_ParticipantsList", ImVec2(0, 0), true); ImGui::BeginChild("Collab_ParticipantsList", ImVec2(0, 0), true);
{
if (collaboration_state_.participants.empty()) { if (collaboration_state_.participants.empty()) {
ImGui::TextDisabled(ICON_MD_PEOPLE " No participants yet"); ImGui::TextDisabled(ICON_MD_PEOPLE " No participants");
} else { } else {
ImGui::TextColored(collaboration_status_color_, ImGui::TextColored(collaboration_status_color_,
ICON_MD_PEOPLE " Participants (%zu):", ICON_MD_PEOPLE " %zu", collaboration_state_.participants.size());
collaboration_state_.participants.size());
ImGui::Separator();
for (size_t i = 0; i < collaboration_state_.participants.size(); ++i) { for (size_t i = 0; i < collaboration_state_.participants.size(); ++i) {
ImGui::PushID(static_cast<int>(i)); ImGui::PushID(static_cast<int>(i));
ImGui::BulletText(ICON_MD_PERSON " %s", ImGui::BulletText("%s", collaboration_state_.participants[i].c_str());
collaboration_state_.participants[i].c_str());
ImGui::PopID(); ImGui::PopID();
} }
} }
}
ImGui::EndChild(); ImGui::EndChild();
ImGui::PopStyleColor(); ImGui::PopStyleColor();
@@ -1196,8 +1186,6 @@ void AgentChatWidget::RenderCollaborationPanel() {
ImGui::PushID("ControlsColumn"); ImGui::PushID("ControlsColumn");
ImGui::BeginChild("Collab_Controls", ImVec2(0, 0), false); ImGui::BeginChild("Collab_Controls", ImVec2(0, 0), false);
ImGui::Separator();
const bool can_host = const bool can_host =
static_cast<bool>(collaboration_callbacks_.host_session); static_cast<bool>(collaboration_callbacks_.host_session);
const bool can_join = const bool can_join =
@@ -1209,67 +1197,52 @@ void AgentChatWidget::RenderCollaborationPanel() {
// Network mode: Show server URL input with styling // Network mode: Show server URL input with styling
if (collaboration_state_.mode == CollaborationMode::kNetwork) { if (collaboration_state_.mode == CollaborationMode::kNetwork) {
ImGui::TextColored(ImVec4(0.196f, 0.6f, 0.8f, 1.0f), ImGui::TextColored(ImVec4(0.196f, 0.6f, 0.8f, 1.0f), ICON_MD_CLOUD);
ICON_MD_CLOUD " Server URL:"); ImGui::SameLine();
ImGui::SetNextItemWidth(-80); ImGui::SetNextItemWidth(100);
ImGui::InputText("##collab_server_url", server_url_buffer_, ImGui::InputText("##collab_server_url", server_url_buffer_, IM_ARRAYSIZE(server_url_buffer_));
IM_ARRAYSIZE(server_url_buffer_));
ImGui::SameLine(); ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.15f, 0.5f, 0.7f, 0.8f)); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.15f, 0.5f, 0.7f, 0.8f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.196f, 0.6f, 0.8f, 1.0f));
ImVec4(0.196f, 0.6f, 0.8f, 1.0f)); if (ImGui::SmallButton(ICON_MD_LINK "##connect_server_btn")) {
if (ImGui::Button(ICON_MD_LINK "##connect_server_btn")) {
collaboration_state_.server_url = server_url_buffer_; collaboration_state_.server_url = server_url_buffer_;
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show("Connecting to server...", ToastType::kInfo, toast_manager_->Show("Connecting to server...", ToastType::kInfo, 3.0f);
3.0f);
} }
} }
ImGui::PopStyleColor(2); ImGui::PopStyleColor(2);
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Connect to collaboration server"); ImGui::SetTooltip("Connect to collaboration server");
} }
ImGui::Separator();
} }
ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), // Host session
ICON_MD_ADD_CIRCLE " Host New Session:"); ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), ICON_MD_ADD_CIRCLE);
ImGui::SetNextItemWidth(-70);
ImGui::InputTextWithHint("##collab_session_name", "Enter session name...",
session_name_buffer_,
IM_ARRAYSIZE(session_name_buffer_));
ImGui::SameLine(); ImGui::SameLine();
if (!can_host) ImGui::SetNextItemWidth(100);
ImGui::BeginDisabled(); ImGui::InputTextWithHint("##collab_session_name", "Session name...", session_name_buffer_, IM_ARRAYSIZE(session_name_buffer_));
ImGui::SameLine();
if (!can_host) ImGui::BeginDisabled();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.6f, 0.5f, 0.0f, 0.8f)); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.6f, 0.5f, 0.0f, 0.8f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0.843f, 0.0f, 1.0f));
ImVec4(1.0f, 0.843f, 0.0f, 1.0f)); if (ImGui::SmallButton(ICON_MD_ROCKET_LAUNCH "##host_session_btn")) {
if (ImGui::Button(ICON_MD_ROCKET_LAUNCH "##host_session_btn")) {
std::string name = session_name_buffer_; std::string name = session_name_buffer_;
if (name.empty()) { if (name.empty()) {
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show("Enter a session name first", toast_manager_->Show("Enter a session name first", ToastType::kWarning, 3.0f);
ToastType::kWarning, 3.0f);
} }
} else { } else {
auto session_or = collaboration_callbacks_.host_session(name); auto session_or = collaboration_callbacks_.host_session(name);
if (session_or.ok()) { if (session_or.ok()) {
ApplyCollaborationSession(session_or.value(), ApplyCollaborationSession(session_or.value(), /*update_action_timestamp=*/true);
/*update_action_timestamp=*/true); std::snprintf(join_code_buffer_, sizeof(join_code_buffer_), "%s", collaboration_state_.session_id.c_str());
std::snprintf(join_code_buffer_, sizeof(join_code_buffer_), "%s",
collaboration_state_.session_id.c_str());
session_name_buffer_[0] = '\0'; session_name_buffer_[0] = '\0';
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show( toast_manager_->Show(absl::StrFormat("Hosting session %s", collaboration_state_.session_id.c_str()), ToastType::kSuccess, 3.5f);
absl::StrFormat("Hosting session %s",
collaboration_state_.session_id.c_str()),
ToastType::kSuccess, 3.5f);
} }
MarkHistoryDirty(); MarkHistoryDirty();
} else if (toast_manager_) { } else if (toast_manager_) {
toast_manager_->Show(absl::StrFormat("Failed to host: %s", toast_manager_->Show(absl::StrFormat("Failed to host: %s", session_or.status().message()), ToastType::kError, 5.0f);
session_or.status().message()),
ToastType::kError, 5.0f);
} }
} }
} }
@@ -1283,44 +1256,32 @@ void AgentChatWidget::RenderCollaborationPanel() {
ImGui::SetTooltip("Host a new collaboration session"); ImGui::SetTooltip("Host a new collaboration session");
} }
ImGui::Spacing(); // Join session
ImGui::TextColored(ImVec4(0.133f, 0.545f, 0.133f, 1.0f), ImGui::TextColored(ImVec4(0.133f, 0.545f, 0.133f, 1.0f), ICON_MD_LOGIN);
ICON_MD_LOGIN " Join Existing Session:");
ImGui::SetNextItemWidth(-70);
ImGui::InputTextWithHint("##collab_join_code", "Enter session code...",
join_code_buffer_,
IM_ARRAYSIZE(join_code_buffer_));
ImGui::SameLine(); ImGui::SameLine();
if (!can_join) ImGui::SetNextItemWidth(100);
ImGui::BeginDisabled(); ImGui::InputTextWithHint("##collab_join_code", "Session code...", join_code_buffer_, IM_ARRAYSIZE(join_code_buffer_));
ImGui::SameLine();
if (!can_join) ImGui::BeginDisabled();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.1f, 0.4f, 0.1f, 0.8f)); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.1f, 0.4f, 0.1f, 0.8f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.133f, 0.545f, 0.133f, 1.0f));
ImVec4(0.133f, 0.545f, 0.133f, 1.0f)); if (ImGui::SmallButton(ICON_MD_MEETING_ROOM "##join_session_btn")) {
if (ImGui::Button(ICON_MD_MEETING_ROOM "##join_session_btn")) {
std::string code = join_code_buffer_; std::string code = join_code_buffer_;
if (code.empty()) { if (code.empty()) {
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show("Enter a session code first", toast_manager_->Show("Enter a session code first", ToastType::kWarning, 3.0f);
ToastType::kWarning, 3.0f);
} }
} else { } else {
auto session_or = collaboration_callbacks_.join_session(code); auto session_or = collaboration_callbacks_.join_session(code);
if (session_or.ok()) { if (session_or.ok()) {
ApplyCollaborationSession(session_or.value(), ApplyCollaborationSession(session_or.value(), /*update_action_timestamp=*/true);
/*update_action_timestamp=*/true); std::snprintf(join_code_buffer_, sizeof(join_code_buffer_), "%s", collaboration_state_.session_id.c_str());
std::snprintf(join_code_buffer_, sizeof(join_code_buffer_), "%s",
collaboration_state_.session_id.c_str());
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show( toast_manager_->Show(absl::StrFormat("Joined session %s", collaboration_state_.session_id.c_str()), ToastType::kSuccess, 3.5f);
absl::StrFormat("Joined session %s",
collaboration_state_.session_id.c_str()),
ToastType::kSuccess, 3.5f);
} }
MarkHistoryDirty(); MarkHistoryDirty();
} else if (toast_manager_) { } else if (toast_manager_) {
toast_manager_->Show(absl::StrFormat("Failed to join: %s", toast_manager_->Show(absl::StrFormat("Failed to join: %s", session_or.status().message()), ToastType::kError, 5.0f);
session_or.status().message()),
ToastType::kError, 5.0f);
} }
} }
} }
@@ -1334,17 +1295,12 @@ void AgentChatWidget::RenderCollaborationPanel() {
ImGui::SetTooltip("Join an existing collaboration session"); ImGui::SetTooltip("Join an existing collaboration session");
} }
// Leave/Refresh
if (collaboration_state_.active) { if (collaboration_state_.active) {
ImGui::Separator(); if (!can_leave) ImGui::BeginDisabled();
ImGui::Spacing();
if (!can_leave)
ImGui::BeginDisabled();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.7f, 0.2f, 0.2f, 0.8f)); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.7f, 0.2f, 0.2f, 0.8f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.863f, 0.078f, 0.235f, 1.0f));
ImVec4(0.863f, 0.078f, 0.235f, 1.0f)); if (ImGui::SmallButton(ICON_MD_LOGOUT "##leave_session_btn")) {
if (ImGui::Button(ICON_MD_LOGOUT " Leave Session##leave_session_btn",
ImVec2(-1, 0))) {
absl::Status status = collaboration_callbacks_.leave_session absl::Status status = collaboration_callbacks_.leave_session
? collaboration_callbacks_.leave_session() ? collaboration_callbacks_.leave_session()
: absl::OkStatus(); : absl::OkStatus();
@@ -1352,42 +1308,30 @@ void AgentChatWidget::RenderCollaborationPanel() {
collaboration_state_ = CollaborationState{}; collaboration_state_ = CollaborationState{};
join_code_buffer_[0] = '\0'; join_code_buffer_[0] = '\0';
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show("Left collaborative session", ToastType::kInfo, toast_manager_->Show("Left collaborative session", ToastType::kInfo, 3.0f);
3.0f);
} }
MarkHistoryDirty(); MarkHistoryDirty();
} else if (toast_manager_) { } else if (toast_manager_) {
toast_manager_->Show( toast_manager_->Show(absl::StrFormat("Failed to leave: %s", status.message()), ToastType::kError, 5.0f);
absl::StrFormat("Failed to leave: %s", status.message()),
ToastType::kError, 5.0f);
} }
} }
ImGui::PopStyleColor(2); ImGui::PopStyleColor(2);
if (!can_leave) if (!can_leave) ImGui::EndDisabled();
ImGui::EndDisabled();
ImGui::Spacing(); ImGui::SameLine();
ImGui::Separator(); if (!can_refresh) ImGui::BeginDisabled();
if (!can_refresh)
ImGui::BeginDisabled();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.4f, 0.4f, 0.6f, 0.8f)); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.4f, 0.4f, 0.6f, 0.8f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.416f, 0.353f, 0.804f, 1.0f));
ImVec4(0.416f, 0.353f, 0.804f, 1.0f)); if (ImGui::SmallButton(ICON_MD_REFRESH "##refresh_collab_btn")) {
if (ImGui::Button(ICON_MD_REFRESH " Refresh Session##refresh_collab_btn",
ImVec2(-1, 0))) {
RefreshCollaboration(); RefreshCollaboration();
} }
ImGui::PopStyleColor(2); ImGui::PopStyleColor(2);
if (!can_refresh && if (!can_refresh && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
ImGui::SetTooltip("Provide refresh_session callback to enable"); ImGui::SetTooltip("Provide refresh_session callback to enable");
} }
if (!can_refresh) if (!can_refresh) ImGui::EndDisabled();
ImGui::EndDisabled();
} else { } else {
ImGui::Spacing(); ImGui::TextDisabled(ICON_MD_INFO " Start or join a session to collaborate.");
ImGui::TextDisabled(ICON_MD_INFO
" Start or join a session to collaborate.");
} }
ImGui::EndChild(); // Collab_Controls ImGui::EndChild(); // Collab_Controls
@@ -1398,6 +1342,7 @@ void AgentChatWidget::RenderCollaborationPanel() {
ImGui::EndChild(); ImGui::EndChild();
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::PopStyleVar(2);
ImGui::PopID(); // CollabPanel ImGui::PopID(); // CollabPanel
} }
@@ -1810,7 +1755,7 @@ void AgentChatWidget::RenderZ3EDCommandPanel() {
void AgentChatWidget::RenderRomSyncPanel() { void AgentChatWidget::RenderRomSyncPanel() {
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.18f, 0.14f, 0.12f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.18f, 0.14f, 0.12f, 1.0f));
ImGui::BeginChild("RomSync", ImVec2(0, 200), true); ImGui::BeginChild("RomSync", ImVec2(0, 100), true);
ImGui::Text(ICON_MD_STORAGE " ROM State"); ImGui::Text(ICON_MD_STORAGE " ROM State");
ImGui::Separator(); ImGui::Separator();

View File

@@ -4,16 +4,16 @@
#include <fstream> #include <fstream>
#include <memory> #include <memory>
#include "absl/strings/str_format.h"
#include "absl/strings/match.h" #include "absl/strings/match.h"
#include "absl/strings/str_format.h"
#include "absl/time/clock.h" #include "absl/time/clock.h"
#include "app/core/platform/asset_loader.h"
#include "app/editor/agent/agent_chat_widget.h" #include "app/editor/agent/agent_chat_widget.h"
#include "app/editor/agent/agent_collaboration_coordinator.h" #include "app/editor/agent/agent_collaboration_coordinator.h"
#include "app/editor/system/proposal_drawer.h" #include "app/editor/system/proposal_drawer.h"
#include "app/editor/system/toast_manager.h" #include "app/editor/system/toast_manager.h"
#include "app/rom.h"
#include "app/gui/icons.h" #include "app/gui/icons.h"
#include "app/core/platform/asset_loader.h" #include "app/rom.h"
#include "util/file_util.h" #include "util/file_util.h"
#ifdef YAZE_WITH_GRPC #ifdef YAZE_WITH_GRPC
@@ -49,11 +49,13 @@ AgentEditor::AgentEditor() {
current_profile_.tags = {"default", "z3ed"}; current_profile_.tags = {"default", "z3ed"};
// Setup text editors // Setup text editors
prompt_editor_->SetLanguageDefinition(TextEditor::LanguageDefinition::CPlusPlus()); prompt_editor_->SetLanguageDefinition(
TextEditor::LanguageDefinition::CPlusPlus());
prompt_editor_->SetReadOnly(false); prompt_editor_->SetReadOnly(false);
prompt_editor_->SetShowWhitespaces(false); prompt_editor_->SetShowWhitespaces(false);
common_tiles_editor_->SetLanguageDefinition(TextEditor::LanguageDefinition::CPlusPlus()); common_tiles_editor_->SetLanguageDefinition(
TextEditor::LanguageDefinition::CPlusPlus());
common_tiles_editor_->SetReadOnly(false); common_tiles_editor_->SetReadOnly(false);
common_tiles_editor_->SetShowWhitespaces(false); common_tiles_editor_->SetShowWhitespaces(false);
@@ -73,7 +75,8 @@ absl::Status AgentEditor::Load() {
// Try to load all bot profiles // Try to load all bot profiles
auto profiles_dir = GetProfilesDirectory(); auto profiles_dir = GetProfilesDirectory();
if (std::filesystem::exists(profiles_dir)) { if (std::filesystem::exists(profiles_dir)) {
for (const auto& entry : std::filesystem::directory_iterator(profiles_dir)) { for (const auto& entry :
std::filesystem::directory_iterator(profiles_dir)) {
if (entry.path().extension() == ".json") { if (entry.path().extension() == ".json") {
std::ifstream file(entry.path()); std::ifstream file(entry.path());
if (file.is_open()) { if (file.is_open()) {
@@ -96,7 +99,8 @@ absl::Status AgentEditor::Save() {
} }
absl::Status AgentEditor::Update() { absl::Status AgentEditor::Update() {
if (!active_) return absl::OkStatus(); if (!active_)
return absl::OkStatus();
// Draw configuration dashboard // Draw configuration dashboard
DrawDashboard(); DrawDashboard();
@@ -133,10 +137,12 @@ void AgentEditor::SetRomContext(Rom* rom) {
} }
void AgentEditor::DrawDashboard() { void AgentEditor::DrawDashboard() {
if (!active_) return; if (!active_)
return;
ImGui::SetNextWindowSize(ImVec2(1200, 800), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(1200, 800), ImGuiCond_FirstUseEver);
ImGui::Begin(ICON_MD_SMART_TOY " AI Agent Platform & Bot Creator", &active_, ImGuiWindowFlags_MenuBar); ImGui::Begin(ICON_MD_SMART_TOY " AI Agent Platform & Bot Creator", &active_,
ImGuiWindowFlags_MenuBar);
// Menu bar // Menu bar
if (ImGui::BeginMenuBar()) { if (ImGui::BeginMenuBar()) {
@@ -150,13 +156,15 @@ void AgentEditor::DrawDashboard() {
if (ImGui::MenuItem(ICON_MD_FILE_UPLOAD " Export Profile...")) { if (ImGui::MenuItem(ICON_MD_FILE_UPLOAD " Export Profile...")) {
// TODO: Open file dialog for export // TODO: Open file dialog for export
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show("Export functionality coming soon", ToastType::kInfo); toast_manager_->Show("Export functionality coming soon",
ToastType::kInfo);
} }
} }
if (ImGui::MenuItem(ICON_MD_FILE_DOWNLOAD " Import Profile...")) { if (ImGui::MenuItem(ICON_MD_FILE_DOWNLOAD " Import Profile...")) {
// TODO: Open file dialog for import // TODO: Open file dialog for import
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show("Import functionality coming soon", ToastType::kInfo); toast_manager_->Show("Import functionality coming soon",
ToastType::kInfo);
} }
} }
ImGui::EndMenu(); ImGui::EndMenu();
@@ -167,10 +175,14 @@ void AgentEditor::DrawDashboard() {
OpenChatWindow(); OpenChatWindow();
} }
ImGui::Separator(); ImGui::Separator();
ImGui::MenuItem(ICON_MD_EDIT " Show Prompt Editor", nullptr, &show_prompt_editor_); ImGui::MenuItem(ICON_MD_EDIT " Show Prompt Editor", nullptr,
ImGui::MenuItem(ICON_MD_FOLDER " Show Bot Profiles", nullptr, &show_bot_profiles_); &show_prompt_editor_);
ImGui::MenuItem(ICON_MD_HISTORY " Show Chat History", nullptr, &show_chat_history_); ImGui::MenuItem(ICON_MD_FOLDER " Show Bot Profiles", nullptr,
ImGui::MenuItem(ICON_MD_ANALYTICS " Show Metrics Dashboard", nullptr, &show_metrics_dashboard_); &show_bot_profiles_);
ImGui::MenuItem(ICON_MD_HISTORY " Show Chat History", nullptr,
&show_chat_history_);
ImGui::MenuItem(ICON_MD_ANALYTICS " Show Metrics Dashboard", nullptr,
&show_metrics_dashboard_);
ImGui::EndMenu(); ImGui::EndMenu();
} }
@@ -189,9 +201,11 @@ void AgentEditor::DrawDashboard() {
ImGuiTableFlags_SizingStretchProp; ImGuiTableFlags_SizingStretchProp;
if (ImGui::BeginTable("BotStudioLayout", 3, table_flags)) { if (ImGui::BeginTable("BotStudioLayout", 3, table_flags)) {
ImGui::TableSetupColumn("Settings", ImGuiTableColumnFlags_WidthFixed, 320.0f); ImGui::TableSetupColumn("Settings", ImGuiTableColumnFlags_WidthFixed,
320.0f);
ImGui::TableSetupColumn("Editors", ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("Editors", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("Profiles", ImGuiTableColumnFlags_WidthFixed, 280.0f); ImGui::TableSetupColumn("Profiles", ImGuiTableColumnFlags_WidthFixed,
280.0f);
ImGui::TableNextRow(); ImGui::TableNextRow();
// Column 1: AI Provider, Behavior, ROM, Tips, Metrics (merged!) // Column 1: AI Provider, Behavior, ROM, Tips, Metrics (merged!)
@@ -249,9 +263,13 @@ void AgentEditor::DrawDashboard() {
ImGui::Spacing(); ImGui::Spacing();
// Two-column layout // Two-column layout
if (ImGui::BeginTable("SessionLayout", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersInnerV)) { if (ImGui::BeginTable(
ImGui::TableSetupColumn("History", ImGuiTableColumnFlags_WidthStretch, 0.6f); "SessionLayout", 2,
ImGui::TableSetupColumn("Metrics", ImGuiTableColumnFlags_WidthStretch, 0.4f); ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersInnerV)) {
ImGui::TableSetupColumn("History", ImGuiTableColumnFlags_WidthStretch,
0.6f);
ImGui::TableSetupColumn("Metrics", ImGuiTableColumnFlags_WidthStretch,
0.4f);
ImGui::TableNextRow(); ImGui::TableNextRow();
// LEFT: Chat History // LEFT: Chat History
@@ -275,18 +293,12 @@ void AgentEditor::DrawDashboard() {
} }
void AgentEditor::DrawConfigurationPanel() { void AgentEditor::DrawConfigurationPanel() {
// Two-column layout
if (ImGui::BeginTable("ConfigLayout", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersInnerV)) {
ImGui::TableSetupColumn("Settings", ImGuiTableColumnFlags_WidthStretch, 0.6f);
ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthStretch, 0.4f);
ImGui::TableNextRow();
// LEFT: Configuration
ImGui::TableSetColumnIndex(0);
// AI Provider Configuration // AI Provider Configuration
if (ImGui::CollapsingHeader(ICON_MD_SETTINGS " AI Provider", ImGuiTreeNodeFlags_DefaultOpen)) { if (ImGui::CollapsingHeader(ICON_MD_SETTINGS " AI Provider",
ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), ICON_MD_SMART_TOY " Provider Selection"); ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f),
ICON_MD_SMART_TOY " Provider Selection");
ImGui::Spacing(); ImGui::Spacing();
// Provider buttons (large, visual) // Provider buttons (large, visual)
@@ -296,51 +308,63 @@ void AgentEditor::DrawConfigurationPanel() {
bool is_ollama = (current_profile_.provider == "ollama"); bool is_ollama = (current_profile_.provider == "ollama");
bool is_gemini = (current_profile_.provider == "gemini"); bool is_gemini = (current_profile_.provider == "gemini");
if (is_mock) ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.6f, 0.6f, 0.6f, 0.8f)); if (is_mock)
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.6f, 0.6f, 0.6f, 0.8f));
if (ImGui::Button(ICON_MD_SETTINGS " Mock", button_size)) { if (ImGui::Button(ICON_MD_SETTINGS " Mock", button_size)) {
current_profile_.provider = "mock"; current_profile_.provider = "mock";
} }
if (is_mock) ImGui::PopStyleColor(); if (is_mock)
ImGui::PopStyleColor();
ImGui::SameLine(); ImGui::SameLine();
if (is_ollama) ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.8f, 0.4f, 0.8f)); if (is_ollama)
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.8f, 0.4f, 0.8f));
if (ImGui::Button(ICON_MD_CLOUD " Ollama", button_size)) { if (ImGui::Button(ICON_MD_CLOUD " Ollama", button_size)) {
current_profile_.provider = "ollama"; current_profile_.provider = "ollama";
} }
if (is_ollama) ImGui::PopStyleColor(); if (is_ollama)
ImGui::PopStyleColor();
ImGui::SameLine(); ImGui::SameLine();
if (is_gemini) ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.196f, 0.6f, 0.8f, 0.8f)); if (is_gemini)
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.196f, 0.6f, 0.8f, 0.8f));
if (ImGui::Button(ICON_MD_SMART_TOY " Gemini", button_size)) { if (ImGui::Button(ICON_MD_SMART_TOY " Gemini", button_size)) {
current_profile_.provider = "gemini"; current_profile_.provider = "gemini";
} }
if (is_gemini) ImGui::PopStyleColor(); if (is_gemini)
ImGui::PopStyleColor();
ImGui::Separator(); ImGui::Separator();
ImGui::Spacing(); ImGui::Spacing();
// Provider-specific settings // Provider-specific settings
if (current_profile_.provider == "ollama") { if (current_profile_.provider == "ollama") {
ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.4f, 1.0f), ICON_MD_SETTINGS " Ollama Settings"); ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.4f, 1.0f),
ICON_MD_SETTINGS " Ollama Settings");
ImGui::Text("Model:"); ImGui::Text("Model:");
ImGui::SetNextItemWidth(-1); ImGui::SetNextItemWidth(-1);
static char model_buf[128] = "qwen2.5-coder:7b"; static char model_buf[128] = "qwen2.5-coder:7b";
if (!current_profile_.model.empty()) { if (!current_profile_.model.empty()) {
strncpy(model_buf, current_profile_.model.c_str(), sizeof(model_buf) - 1); strncpy(model_buf, current_profile_.model.c_str(),
sizeof(model_buf) - 1);
} }
if (ImGui::InputTextWithHint("##ollama_model", "e.g., qwen2.5-coder:7b, llama3.2", model_buf, sizeof(model_buf))) { if (ImGui::InputTextWithHint("##ollama_model",
"e.g., qwen2.5-coder:7b, llama3.2",
model_buf, sizeof(model_buf))) {
current_profile_.model = model_buf; current_profile_.model = model_buf;
} }
ImGui::Text("Host URL:"); ImGui::Text("Host URL:");
ImGui::SetNextItemWidth(-1); ImGui::SetNextItemWidth(-1);
static char host_buf[256] = "http://localhost:11434"; static char host_buf[256] = "http://localhost:11434";
strncpy(host_buf, current_profile_.ollama_host.c_str(), sizeof(host_buf) - 1); strncpy(host_buf, current_profile_.ollama_host.c_str(),
sizeof(host_buf) - 1);
if (ImGui::InputText("##ollama_host", host_buf, sizeof(host_buf))) { if (ImGui::InputText("##ollama_host", host_buf, sizeof(host_buf))) {
current_profile_.ollama_host = host_buf; current_profile_.ollama_host = host_buf;
} }
} else if (current_profile_.provider == "gemini") { } else if (current_profile_.provider == "gemini") {
ImGui::TextColored(ImVec4(0.196f, 0.6f, 0.8f, 1.0f), ICON_MD_SMART_TOY " Gemini Settings"); ImGui::TextColored(ImVec4(0.196f, 0.6f, 0.8f, 1.0f),
ICON_MD_SMART_TOY " Gemini Settings");
// Load from environment button // Load from environment button
if (ImGui::Button(ICON_MD_REFRESH " Load from Environment")) { if (ImGui::Button(ICON_MD_REFRESH " Load from Environment")) {
@@ -353,7 +377,8 @@ void AgentEditor::DrawConfigurationPanel() {
} }
} else { } else {
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show("GEMINI_API_KEY not found", ToastType::kWarning); toast_manager_->Show("GEMINI_API_KEY not found",
ToastType::kWarning);
} }
} }
} }
@@ -364,9 +389,11 @@ void AgentEditor::DrawConfigurationPanel() {
ImGui::SetNextItemWidth(-1); ImGui::SetNextItemWidth(-1);
static char model_buf[128] = "gemini-1.5-flash"; static char model_buf[128] = "gemini-1.5-flash";
if (!current_profile_.model.empty()) { if (!current_profile_.model.empty()) {
strncpy(model_buf, current_profile_.model.c_str(), sizeof(model_buf) - 1); strncpy(model_buf, current_profile_.model.c_str(),
sizeof(model_buf) - 1);
} }
if (ImGui::InputTextWithHint("##gemini_model", "e.g., gemini-1.5-flash", model_buf, sizeof(model_buf))) { if (ImGui::InputTextWithHint("##gemini_model", "e.g., gemini-1.5-flash",
model_buf, sizeof(model_buf))) {
current_profile_.model = model_buf; current_profile_.model = model_buf;
} }
@@ -374,13 +401,16 @@ void AgentEditor::DrawConfigurationPanel() {
ImGui::SetNextItemWidth(-1); ImGui::SetNextItemWidth(-1);
static char key_buf[256] = ""; static char key_buf[256] = "";
if (!current_profile_.gemini_api_key.empty() && key_buf[0] == '\0') { if (!current_profile_.gemini_api_key.empty() && key_buf[0] == '\0') {
strncpy(key_buf, current_profile_.gemini_api_key.c_str(), sizeof(key_buf) - 1); strncpy(key_buf, current_profile_.gemini_api_key.c_str(),
sizeof(key_buf) - 1);
} }
if (ImGui::InputText("##gemini_key", key_buf, sizeof(key_buf), ImGuiInputTextFlags_Password)) { if (ImGui::InputText("##gemini_key", key_buf, sizeof(key_buf),
ImGuiInputTextFlags_Password)) {
current_profile_.gemini_api_key = key_buf; current_profile_.gemini_api_key = key_buf;
} }
if (!current_profile_.gemini_api_key.empty()) { if (!current_profile_.gemini_api_key.empty()) {
ImGui::TextColored(ImVec4(0.133f, 0.545f, 0.133f, 1.0f), ICON_MD_CHECK_CIRCLE " API key configured"); ImGui::TextColored(ImVec4(0.133f, 0.545f, 0.133f, 1.0f),
ICON_MD_CHECK_CIRCLE " API key configured");
} }
} else { } else {
ImGui::TextDisabled(ICON_MD_INFO " Mock mode - no configuration needed"); ImGui::TextDisabled(ICON_MD_INFO " Mock mode - no configuration needed");
@@ -388,11 +418,16 @@ void AgentEditor::DrawConfigurationPanel() {
} }
// Behavior Settings // Behavior Settings
if (ImGui::CollapsingHeader(ICON_MD_TUNE " Behavior", ImGuiTreeNodeFlags_DefaultOpen)) { if (ImGui::CollapsingHeader(ICON_MD_TUNE " Behavior",
ImGui::Checkbox(ICON_MD_VISIBILITY " Show Reasoning", &current_profile_.show_reasoning); ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Checkbox(ICON_MD_ANALYTICS " Verbose Output", &current_profile_.verbose); ImGui::Checkbox(ICON_MD_VISIBILITY " Show Reasoning",
ImGui::SliderInt(ICON_MD_LOOP " Max Tool Iterations", &current_profile_.max_tool_iterations, 1, 10); &current_profile_.show_reasoning);
ImGui::SliderInt(ICON_MD_REFRESH " Max Retry Attempts", &current_profile_.max_retry_attempts, 1, 10); ImGui::Checkbox(ICON_MD_ANALYTICS " Verbose Output",
&current_profile_.verbose);
ImGui::SliderInt(ICON_MD_LOOP " Max Tool Iterations",
&current_profile_.max_tool_iterations, 1, 10);
ImGui::SliderInt(ICON_MD_REFRESH " Max Retry Attempts",
&current_profile_.max_retry_attempts, 1, 10);
} }
// Profile Metadata // Profile Metadata
@@ -406,8 +441,10 @@ void AgentEditor::DrawConfigurationPanel() {
ImGui::Text("Description:"); ImGui::Text("Description:");
static char desc_buf[256]; static char desc_buf[256];
strncpy(desc_buf, current_profile_.description.c_str(), sizeof(desc_buf) - 1); strncpy(desc_buf, current_profile_.description.c_str(),
if (ImGui::InputTextMultiline("##profile_desc", desc_buf, sizeof(desc_buf), ImVec2(-1, 60))) { sizeof(desc_buf) - 1);
if (ImGui::InputTextMultiline("##profile_desc", desc_buf, sizeof(desc_buf),
ImVec2(-1, 60))) {
current_profile_.description = desc_buf; current_profile_.description = desc_buf;
} }
@@ -416,7 +453,8 @@ void AgentEditor::DrawConfigurationPanel() {
if (tags_buf[0] == '\0' && !current_profile_.tags.empty()) { if (tags_buf[0] == '\0' && !current_profile_.tags.empty()) {
std::string tags_str; std::string tags_str;
for (size_t i = 0; i < current_profile_.tags.size(); ++i) { for (size_t i = 0; i < current_profile_.tags.size(); ++i) {
if (i > 0) tags_str += ", "; if (i > 0)
tags_str += ", ";
tags_str += current_profile_.tags[i]; tags_str += current_profile_.tags[i];
} }
strncpy(tags_buf, tags_str.c_str(), sizeof(tags_buf) - 1); strncpy(tags_buf, tags_str.c_str(), sizeof(tags_buf) - 1);
@@ -449,8 +487,10 @@ void AgentEditor::DrawConfigurationPanel() {
// Apply button // Apply button
ImGui::Spacing(); ImGui::Spacing();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.133f, 0.545f, 0.133f, 0.8f)); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.133f, 0.545f, 0.133f, 0.8f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.133f, 0.545f, 0.133f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
if (ImGui::Button(ICON_MD_CHECK " Apply & Save Configuration", ImVec2(-1, 40))) { ImVec4(0.133f, 0.545f, 0.133f, 1.0f));
if (ImGui::Button(ICON_MD_CHECK " Apply & Save Configuration",
ImVec2(-1, 40))) {
// Update legacy config // Update legacy config
current_config_.provider = current_profile_.provider; current_config_.provider = current_profile_.provider;
current_config_.model = current_profile_.model; current_config_.model = current_profile_.model;
@@ -464,19 +504,13 @@ void AgentEditor::DrawConfigurationPanel() {
Save(); Save();
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show("Configuration applied and saved", ToastType::kSuccess); toast_manager_->Show("Configuration applied and saved",
ToastType::kSuccess);
} }
} }
ImGui::PopStyleColor(2); ImGui::PopStyleColor(2);
// RIGHT: Status & Quick Info
ImGui::TableSetColumnIndex(1);
DrawStatusPanel();
DrawMetricsPanel(); DrawMetricsPanel();
ImGui::EndTable();
}
} }
void AgentEditor::DrawStatusPanel() { void AgentEditor::DrawStatusPanel() {
@@ -488,7 +522,8 @@ void AgentEditor::DrawStatusPanel() {
ImGui::Separator(); ImGui::Separator();
if (chat_widget_ && chat_widget_->is_active()) { if (chat_widget_ && chat_widget_->is_active()) {
ImGui::TextColored(ImVec4(0.133f, 0.545f, 0.133f, 1.0f), ICON_MD_CHECK_CIRCLE " Active"); ImGui::TextColored(ImVec4(0.133f, 0.545f, 0.133f, 1.0f),
ICON_MD_CHECK_CIRCLE " Active");
} else { } else {
ImGui::TextDisabled(ICON_MD_CANCEL " Inactive"); ImGui::TextDisabled(ICON_MD_CANCEL " Inactive");
} }
@@ -507,11 +542,13 @@ void AgentEditor::DrawStatusPanel() {
ImGui::Separator(); ImGui::Separator();
if (rom_ && rom_->is_loaded()) { if (rom_ && rom_->is_loaded()) {
ImGui::TextColored(ImVec4(0.133f, 0.545f, 0.133f, 1.0f), ICON_MD_CHECK_CIRCLE " Loaded"); ImGui::TextColored(ImVec4(0.133f, 0.545f, 0.133f, 1.0f),
ICON_MD_CHECK_CIRCLE " Loaded");
ImGui::TextDisabled("Title: %s", rom_->title().c_str()); ImGui::TextDisabled("Title: %s", rom_->title().c_str());
ImGui::TextDisabled("Tools: Ready"); ImGui::TextDisabled("Tools: Ready");
} else { } else {
ImGui::TextColored(ImVec4(0.8f, 0.2f, 0.2f, 1.0f), ICON_MD_WARNING " Not Loaded"); ImGui::TextColored(ImVec4(0.8f, 0.2f, 0.2f, 1.0f),
ICON_MD_WARNING " Not Loaded");
ImGui::TextDisabled("Load ROM for AI tools"); ImGui::TextDisabled("Load ROM for AI tools");
} }
ImGui::EndChild(); ImGui::EndChild();
@@ -520,7 +557,8 @@ void AgentEditor::DrawStatusPanel() {
// Quick Tips Card // Quick Tips Card
ImGui::BeginChild("QuickTipsCard", ImVec2(0, 150), true); ImGui::BeginChild("QuickTipsCard", ImVec2(0, 150), true);
ImGui::TextColored(ImVec4(0.196f, 0.6f, 0.8f, 1.0f), ICON_MD_TIPS_AND_UPDATES " Quick Tips"); ImGui::TextColored(ImVec4(0.196f, 0.6f, 0.8f, 1.0f),
ICON_MD_TIPS_AND_UPDATES " Quick Tips");
ImGui::Separator(); ImGui::Separator();
ImGui::Spacing(); ImGui::Spacing();
@@ -545,7 +583,8 @@ void AgentEditor::DrawMetricsPanel() {
} }
void AgentEditor::DrawPromptEditorPanel() { void AgentEditor::DrawPromptEditorPanel() {
ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), ICON_MD_EDIT " Prompt Editor"); ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f),
ICON_MD_EDIT " Prompt Editor");
ImGui::Separator(); ImGui::Separator();
ImGui::Spacing(); ImGui::Spacing();
@@ -553,15 +592,18 @@ void AgentEditor::DrawPromptEditorPanel() {
ImGui::Text("File:"); ImGui::Text("File:");
ImGui::SetNextItemWidth(-45); ImGui::SetNextItemWidth(-45);
if (ImGui::BeginCombo("##prompt_file", active_prompt_file_.c_str())) { if (ImGui::BeginCombo("##prompt_file", active_prompt_file_.c_str())) {
if (ImGui::Selectable("system_prompt.txt", active_prompt_file_ == "system_prompt.txt")) { if (ImGui::Selectable("system_prompt.txt",
active_prompt_file_ == "system_prompt.txt")) {
active_prompt_file_ = "system_prompt.txt"; active_prompt_file_ = "system_prompt.txt";
prompt_editor_initialized_ = false; prompt_editor_initialized_ = false;
} }
if (ImGui::Selectable("system_prompt_v2.txt", active_prompt_file_ == "system_prompt_v2.txt")) { if (ImGui::Selectable("system_prompt_v2.txt",
active_prompt_file_ == "system_prompt_v2.txt")) {
active_prompt_file_ = "system_prompt_v2.txt"; active_prompt_file_ = "system_prompt_v2.txt";
prompt_editor_initialized_ = false; prompt_editor_initialized_ = false;
} }
if (ImGui::Selectable("system_prompt_v3.txt", active_prompt_file_ == "system_prompt_v3.txt")) { if (ImGui::Selectable("system_prompt_v3.txt",
active_prompt_file_ == "system_prompt_v3.txt")) {
active_prompt_file_ = "system_prompt_v3.txt"; active_prompt_file_ = "system_prompt_v3.txt";
prompt_editor_initialized_ = false; prompt_editor_initialized_ = false;
} }
@@ -587,8 +629,8 @@ void AgentEditor::DrawPromptEditorPanel() {
prompt_editor_initialized_ = true; prompt_editor_initialized_ = true;
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show( toast_manager_->Show(absl::StrFormat(ICON_MD_CHECK_CIRCLE " Loaded %s",
absl::StrFormat(ICON_MD_CHECK_CIRCLE " Loaded %s", active_prompt_file_), active_prompt_file_),
ToastType::kSuccess, 2.0f); ToastType::kSuccess, 2.0f);
} }
} else { } else {
@@ -603,11 +645,10 @@ void AgentEditor::DrawPromptEditorPanel() {
"# Please ensure the file exists in:\n" "# Please ensure the file exists in:\n"
"# - assets/agent/%s\n" "# - assets/agent/%s\n"
"# - Or Contents/Resources/agent/%s (macOS bundle)\n\n" "# - Or Contents/Resources/agent/%s (macOS bundle)\n\n"
"# You can create a custom prompt here and save it to your bot profile.", "# You can create a custom prompt here and save it to your bot "
active_prompt_file_, "profile.",
content_result.status().message(), active_prompt_file_, content_result.status().message(),
active_prompt_file_, active_prompt_file_, active_prompt_file_);
active_prompt_file_);
prompt_editor_->SetText(placeholder); prompt_editor_->SetText(placeholder);
prompt_editor_initialized_ = true; prompt_editor_initialized_ = true;
@@ -627,23 +668,28 @@ void AgentEditor::DrawPromptEditorPanel() {
if (ImGui::Button(ICON_MD_SAVE " Save Prompt to Profile", ImVec2(-1, 0))) { if (ImGui::Button(ICON_MD_SAVE " Save Prompt to Profile", ImVec2(-1, 0))) {
current_profile_.system_prompt = prompt_editor_->GetText(); current_profile_.system_prompt = prompt_editor_->GetText();
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show("System prompt saved to profile", ToastType::kSuccess); toast_manager_->Show("System prompt saved to profile",
ToastType::kSuccess);
} }
} }
} }
ImGui::Spacing(); ImGui::Spacing();
ImGui::TextWrapped("Edit the system prompt that guides the AI agent's behavior. Changes are saved to the current bot profile."); ImGui::TextWrapped(
"Edit the system prompt that guides the AI agent's behavior. Changes are "
"saved to the current bot profile.");
} }
void AgentEditor::DrawBotProfilesPanel() { void AgentEditor::DrawBotProfilesPanel() {
ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), ICON_MD_FOLDER " Bot Profile Manager"); ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f),
ICON_MD_FOLDER " Bot Profile Manager");
ImGui::Separator(); ImGui::Separator();
ImGui::Spacing(); ImGui::Spacing();
// Current profile display // Current profile display
ImGui::BeginChild("CurrentProfile", ImVec2(0, 150), true); ImGui::BeginChild("CurrentProfile", ImVec2(0, 150), true);
ImGui::TextColored(ImVec4(0.196f, 0.6f, 0.8f, 1.0f), ICON_MD_STAR " Current Profile"); ImGui::TextColored(ImVec4(0.196f, 0.6f, 0.8f, 1.0f),
ICON_MD_STAR " Current Profile");
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Name: %s", current_profile_.name.c_str()); ImGui::Text("Name: %s", current_profile_.name.c_str());
ImGui::Text("Provider: %s", current_profile_.provider.c_str()); ImGui::Text("Provider: %s", current_profile_.provider.c_str());
@@ -651,7 +697,9 @@ void AgentEditor::DrawBotProfilesPanel() {
ImGui::Text("Model: %s", current_profile_.model.c_str()); ImGui::Text("Model: %s", current_profile_.model.c_str());
} }
ImGui::TextWrapped("Description: %s", ImGui::TextWrapped("Description: %s",
current_profile_.description.empty() ? "No description" : current_profile_.description.c_str()); current_profile_.description.empty()
? "No description"
: current_profile_.description.c_str());
ImGui::EndChild(); ImGui::EndChild();
ImGui::Spacing(); ImGui::Spacing();
@@ -665,20 +713,23 @@ void AgentEditor::DrawBotProfilesPanel() {
new_profile.modified_at = absl::Now(); new_profile.modified_at = absl::Now();
current_profile_ = new_profile; current_profile_ = new_profile;
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show("New profile created. Configure and save it.", ToastType::kInfo); toast_manager_->Show("New profile created. Configure and save it.",
ToastType::kInfo);
} }
} }
ImGui::Spacing(); ImGui::Spacing();
// Saved profiles list // Saved profiles list
ImGui::TextColored(ImVec4(0.196f, 0.6f, 0.8f, 1.0f), ICON_MD_LIST " Saved Profiles"); ImGui::TextColored(ImVec4(0.196f, 0.6f, 0.8f, 1.0f),
ICON_MD_LIST " Saved Profiles");
ImGui::Separator(); ImGui::Separator();
ImGui::BeginChild("ProfilesList", ImVec2(0, 0), true); ImGui::BeginChild("ProfilesList", ImVec2(0, 0), true);
if (loaded_profiles_.empty()) { if (loaded_profiles_.empty()) {
ImGui::TextDisabled("No saved profiles. Create and save a profile to see it here."); ImGui::TextDisabled(
"No saved profiles. Create and save a profile to see it here.");
} else { } else {
for (size_t i = 0; i < loaded_profiles_.size(); ++i) { for (size_t i = 0; i < loaded_profiles_.size(); ++i) {
const auto& profile = loaded_profiles_[i]; const auto& profile = loaded_profiles_[i];
@@ -686,13 +737,17 @@ void AgentEditor::DrawBotProfilesPanel() {
bool is_current = (profile.name == current_profile_.name); bool is_current = (profile.name == current_profile_.name);
if (is_current) { if (is_current) {
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.196f, 0.6f, 0.8f, 0.6f)); ImGui::PushStyleColor(ImGuiCol_Button,
ImVec4(0.196f, 0.6f, 0.8f, 0.6f));
} }
if (ImGui::Button(profile.name.c_str(), ImVec2(ImGui::GetContentRegionAvail().x - 80, 0))) { if (ImGui::Button(profile.name.c_str(),
ImVec2(ImGui::GetContentRegionAvail().x - 80, 0))) {
LoadBotProfile(profile.name); LoadBotProfile(profile.name);
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show(absl::StrFormat("Loaded profile: %s", profile.name), ToastType::kSuccess); toast_manager_->Show(
absl::StrFormat("Loaded profile: %s", profile.name),
ToastType::kSuccess);
} }
} }
@@ -705,13 +760,17 @@ void AgentEditor::DrawBotProfilesPanel() {
if (ImGui::SmallButton(ICON_MD_DELETE)) { if (ImGui::SmallButton(ICON_MD_DELETE)) {
DeleteBotProfile(profile.name); DeleteBotProfile(profile.name);
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show(absl::StrFormat("Deleted profile: %s", profile.name), ToastType::kInfo); toast_manager_->Show(
absl::StrFormat("Deleted profile: %s", profile.name),
ToastType::kInfo);
} }
} }
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::TextDisabled(" %s | %s", profile.provider.c_str(), ImGui::TextDisabled(" %s | %s", profile.provider.c_str(),
profile.description.empty() ? "No description" : profile.description.c_str()); profile.description.empty()
? "No description"
: profile.description.c_str());
ImGui::Spacing(); ImGui::Spacing();
ImGui::PopID(); ImGui::PopID();
@@ -722,7 +781,8 @@ void AgentEditor::DrawBotProfilesPanel() {
} }
void AgentEditor::DrawChatHistoryViewer() { void AgentEditor::DrawChatHistoryViewer() {
ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), ICON_MD_HISTORY " Chat History Viewer"); ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f),
ICON_MD_HISTORY " Chat History Viewer");
ImGui::Separator(); ImGui::Separator();
ImGui::Spacing(); ImGui::Spacing();
@@ -753,18 +813,22 @@ void AgentEditor::DrawChatHistoryViewer() {
ImGui::BeginChild("HistoryList", ImVec2(0, 0), true); ImGui::BeginChild("HistoryList", ImVec2(0, 0), true);
if (cached_history_.empty()) { if (cached_history_.empty()) {
ImGui::TextDisabled("No chat history. Start a conversation in the chat window."); ImGui::TextDisabled(
"No chat history. Start a conversation in the chat window.");
} else { } else {
for (const auto& msg : cached_history_) { for (const auto& msg : cached_history_) {
bool from_user = (msg.sender == cli::agent::ChatMessage::Sender::kUser); bool from_user = (msg.sender == cli::agent::ChatMessage::Sender::kUser);
ImVec4 color = from_user ? ImVec4(0.6f, 0.8f, 1.0f, 1.0f) : ImVec4(0.4f, 0.8f, 0.4f, 1.0f); ImVec4 color = from_user ? ImVec4(0.6f, 0.8f, 1.0f, 1.0f)
: ImVec4(0.4f, 0.8f, 0.4f, 1.0f);
ImGui::PushStyleColor(ImGuiCol_Text, color); ImGui::PushStyleColor(ImGuiCol_Text, color);
ImGui::Text("%s:", from_user ? "User" : "Agent"); ImGui::Text("%s:", from_user ? "User" : "Agent");
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::SameLine(); ImGui::SameLine();
ImGui::TextDisabled("%s", absl::FormatTime("%H:%M:%S", msg.timestamp, absl::LocalTimeZone()).c_str()); ImGui::TextDisabled("%s", absl::FormatTime("%H:%M:%S", msg.timestamp,
absl::LocalTimeZone())
.c_str());
ImGui::TextWrapped("%s", msg.message.c_str()); ImGui::TextWrapped("%s", msg.message.c_str());
ImGui::Spacing(); ImGui::Spacing();
@@ -776,15 +840,18 @@ void AgentEditor::DrawChatHistoryViewer() {
} }
void AgentEditor::DrawAdvancedMetricsPanel() { void AgentEditor::DrawAdvancedMetricsPanel() {
ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), ICON_MD_ANALYTICS " Session Metrics & Analytics"); ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f),
ICON_MD_ANALYTICS " Session Metrics & Analytics");
ImGui::Separator(); ImGui::Separator();
ImGui::Spacing(); ImGui::Spacing();
// Get metrics from chat widget service // Get metrics from chat widget service
if (chat_widget_) { if (chat_widget_) {
// For now show placeholder metrics structure // For now show placeholder metrics structure
if (ImGui::BeginTable("MetricsTable", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { if (ImGui::BeginTable("MetricsTable", 2,
ImGui::TableSetupColumn("Metric", ImGuiTableColumnFlags_WidthFixed, 200.0f); ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
ImGui::TableSetupColumn("Metric", ImGuiTableColumnFlags_WidthFixed,
200.0f);
ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableHeadersRow(); ImGui::TableHeadersRow();
@@ -816,18 +883,23 @@ void AgentEditor::DrawAdvancedMetricsPanel() {
} }
ImGui::Spacing(); ImGui::Spacing();
ImGui::TextWrapped("Detailed session metrics are available during active chat sessions. Open the chat window to see live statistics."); ImGui::TextWrapped(
"Detailed session metrics are available during active chat sessions. "
"Open the chat window to see live statistics.");
} else { } else {
ImGui::TextDisabled("No metrics available. Initialize the chat system first."); ImGui::TextDisabled(
"No metrics available. Initialize the chat system first.");
} }
} }
void AgentEditor::DrawCommonTilesEditor() { void AgentEditor::DrawCommonTilesEditor() {
ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), ICON_MD_GRID_ON " Common Tiles Reference"); ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f),
ICON_MD_GRID_ON " Common Tiles Reference");
ImGui::Separator(); ImGui::Separator();
ImGui::Spacing(); ImGui::Spacing();
ImGui::TextWrapped("Customize the tile reference file that AI uses for tile placement. " ImGui::TextWrapped(
"Customize the tile reference file that AI uses for tile placement. "
"Organize tiles by category and provide hex IDs with descriptions."); "Organize tiles by category and provide hex IDs with descriptions.");
ImGui::Spacing(); ImGui::Spacing();
@@ -839,7 +911,8 @@ void AgentEditor::DrawCommonTilesEditor() {
common_tiles_editor_->SetText(*content); common_tiles_editor_->SetText(*content);
common_tiles_initialized_ = true; common_tiles_initialized_ = true;
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show(ICON_MD_CHECK_CIRCLE " Common tiles loaded", ToastType::kSuccess, 2.0f); toast_manager_->Show(ICON_MD_CHECK_CIRCLE " Common tiles loaded",
ToastType::kSuccess, 2.0f);
} }
} }
} }
@@ -848,7 +921,9 @@ void AgentEditor::DrawCommonTilesEditor() {
if (ImGui::Button(ICON_MD_SAVE " Save", ImVec2(100, 0))) { if (ImGui::Button(ICON_MD_SAVE " Save", ImVec2(100, 0))) {
// Save to project or assets directory // Save to project or assets directory
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show(ICON_MD_INFO " Save to project directory (coming soon)", ToastType::kInfo, 2.0f); toast_manager_->Show(ICON_MD_INFO
" Save to project directory (coming soon)",
ToastType::kInfo, 2.0f);
} }
} }
@@ -888,17 +963,20 @@ void AgentEditor::DrawCommonTilesEditor() {
// Editor // Editor
if (common_tiles_editor_) { if (common_tiles_editor_) {
ImVec2 editor_size(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y); ImVec2 editor_size(ImGui::GetContentRegionAvail().x,
ImGui::GetContentRegionAvail().y);
common_tiles_editor_->Render("##tiles_editor", editor_size, true); common_tiles_editor_->Render("##tiles_editor", editor_size, true);
} }
} }
void AgentEditor::DrawNewPromptCreator() { void AgentEditor::DrawNewPromptCreator() {
ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), ICON_MD_ADD " Create New System Prompt"); ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f),
ICON_MD_ADD " Create New System Prompt");
ImGui::Separator(); ImGui::Separator();
ImGui::Spacing(); ImGui::Spacing();
ImGui::TextWrapped("Create a custom system prompt from scratch or use a template."); ImGui::TextWrapped(
"Create a custom system prompt from scratch or use a template.");
ImGui::Spacing(); ImGui::Spacing();
ImGui::Separator(); ImGui::Separator();
@@ -925,7 +1003,8 @@ void AgentEditor::DrawNewPromptCreator() {
} }
if (ImGui::Button(ICON_MD_FILE_COPY " v2 (Enhanced)", ImVec2(-1, 0))) { if (ImGui::Button(ICON_MD_FILE_COPY " v2 (Enhanced)", ImVec2(-1, 0))) {
auto content = core::AssetLoader::LoadTextFile("agent/system_prompt_v2.txt"); auto content =
core::AssetLoader::LoadTextFile("agent/system_prompt_v2.txt");
if (content.ok() && prompt_editor_) { if (content.ok() && prompt_editor_) {
prompt_editor_->SetText(*content); prompt_editor_->SetText(*content);
if (toast_manager_) { if (toast_manager_) {
@@ -935,7 +1014,8 @@ void AgentEditor::DrawNewPromptCreator() {
} }
if (ImGui::Button(ICON_MD_FILE_COPY " v3 (Proactive)", ImVec2(-1, 0))) { if (ImGui::Button(ICON_MD_FILE_COPY " v3 (Proactive)", ImVec2(-1, 0))) {
auto content = core::AssetLoader::LoadTextFile("agent/system_prompt_v3.txt"); auto content =
core::AssetLoader::LoadTextFile("agent/system_prompt_v3.txt");
if (content.ok() && prompt_editor_) { if (content.ok() && prompt_editor_) {
prompt_editor_->SetText(*content); prompt_editor_->SetText(*content);
if (toast_manager_) { if (toast_manager_) {
@@ -964,7 +1044,8 @@ void AgentEditor::DrawNewPromptCreator() {
"3. Explain your reasoning\n"; "3. Explain your reasoning\n";
prompt_editor_->SetText(blank_template); prompt_editor_->SetText(blank_template);
if (toast_manager_) { if (toast_manager_) {
toast_manager_->Show("Blank template created", ToastType::kSuccess, 1.5f); toast_manager_->Show("Blank template created", ToastType::kSuccess,
1.5f);
} }
} }
} }
@@ -992,13 +1073,16 @@ void AgentEditor::DrawNewPromptCreator() {
// Clear name buffer // Clear name buffer
std::memset(new_prompt_name_, 0, sizeof(new_prompt_name_)); std::memset(new_prompt_name_, 0, sizeof(new_prompt_name_));
} else if (toast_manager_) { } else if (toast_manager_) {
toast_manager_->Show(ICON_MD_WARNING " Enter a name for the prompt", ToastType::kWarning, 2.0f); toast_manager_->Show(ICON_MD_WARNING " Enter a name for the prompt",
ToastType::kWarning, 2.0f);
} }
} }
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::Spacing(); ImGui::Spacing();
ImGui::TextWrapped("Note: New prompts are saved to your project. Use 'System Prompt' tab to edit existing prompts."); ImGui::TextWrapped(
"Note: New prompts are saved to your project. Use 'System Prompt' tab to "
"edit existing prompts.");
} }
// Bot Profile Management Implementation // Bot Profile Management Implementation
@@ -1006,7 +1090,8 @@ absl::Status AgentEditor::SaveBotProfile(const BotProfile& profile) {
#if defined(YAZE_WITH_JSON) #if defined(YAZE_WITH_JSON)
RETURN_IF_ERROR(EnsureProfilesDirectory()); RETURN_IF_ERROR(EnsureProfilesDirectory());
std::filesystem::path profile_path = GetProfilesDirectory() / (profile.name + ".json"); std::filesystem::path profile_path =
GetProfilesDirectory() / (profile.name + ".json");
std::ofstream file(profile_path); std::ofstream file(profile_path);
if (!file.is_open()) { if (!file.is_open()) {
return absl::InternalError("Failed to open profile file for writing"); return absl::InternalError("Failed to open profile file for writing");
@@ -1020,13 +1105,15 @@ absl::Status AgentEditor::SaveBotProfile(const BotProfile& profile) {
return absl::OkStatus(); return absl::OkStatus();
#else #else
return absl::UnimplementedError("JSON support required for profile management"); return absl::UnimplementedError(
"JSON support required for profile management");
#endif #endif
} }
absl::Status AgentEditor::LoadBotProfile(const std::string& name) { absl::Status AgentEditor::LoadBotProfile(const std::string& name) {
#if defined(YAZE_WITH_JSON) #if defined(YAZE_WITH_JSON)
std::filesystem::path profile_path = GetProfilesDirectory() / (name + ".json"); std::filesystem::path profile_path =
GetProfilesDirectory() / (name + ".json");
if (!std::filesystem::exists(profile_path)) { if (!std::filesystem::exists(profile_path)) {
return absl::NotFoundError(absl::StrFormat("Profile '%s' not found", name)); return absl::NotFoundError(absl::StrFormat("Profile '%s' not found", name));
} }
@@ -1056,12 +1143,14 @@ absl::Status AgentEditor::LoadBotProfile(const std::string& name) {
return absl::OkStatus(); return absl::OkStatus();
#else #else
return absl::UnimplementedError("JSON support required for profile management"); return absl::UnimplementedError(
"JSON support required for profile management");
#endif #endif
} }
absl::Status AgentEditor::DeleteBotProfile(const std::string& name) { absl::Status AgentEditor::DeleteBotProfile(const std::string& name) {
std::filesystem::path profile_path = GetProfilesDirectory() / (name + ".json"); std::filesystem::path profile_path =
GetProfilesDirectory() / (name + ".json");
if (!std::filesystem::exists(profile_path)) { if (!std::filesystem::exists(profile_path)) {
return absl::NotFoundError(absl::StrFormat("Profile '%s' not found", name)); return absl::NotFoundError(absl::StrFormat("Profile '%s' not found", name));
} }
@@ -1091,7 +1180,8 @@ void AgentEditor::SetCurrentProfile(const BotProfile& profile) {
current_config_.max_tool_iterations = profile.max_tool_iterations; current_config_.max_tool_iterations = profile.max_tool_iterations;
} }
absl::Status AgentEditor::ExportProfile(const BotProfile& profile, const std::filesystem::path& path) { absl::Status AgentEditor::ExportProfile(const BotProfile& profile,
const std::filesystem::path& path) {
#if defined(YAZE_WITH_JSON) #if defined(YAZE_WITH_JSON)
std::ofstream file(path); std::ofstream file(path);
if (!file.is_open()) { if (!file.is_open()) {
@@ -1146,7 +1236,8 @@ std::filesystem::path AgentEditor::GetProfilesDirectory() const {
#endif #endif
} }
return config_dir / std::filesystem::path("agent") / std::filesystem::path("profiles"); return config_dir / std::filesystem::path("agent") /
std::filesystem::path("profiles");
} }
absl::Status AgentEditor::EnsureProfilesDirectory() { absl::Status AgentEditor::EnsureProfilesDirectory() {
@@ -1154,7 +1245,8 @@ absl::Status AgentEditor::EnsureProfilesDirectory() {
std::error_code ec; std::error_code ec;
std::filesystem::create_directories(dir, ec); std::filesystem::create_directories(dir, ec);
if (ec) { if (ec) {
return absl::InternalError(absl::StrFormat("Failed to create profiles directory: %s", ec.message())); return absl::InternalError(absl::StrFormat(
"Failed to create profiles directory: %s", ec.message()));
} }
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -1174,8 +1266,10 @@ std::string AgentEditor::ProfileToJson(const BotProfile& profile) const {
json["max_tool_iterations"] = profile.max_tool_iterations; json["max_tool_iterations"] = profile.max_tool_iterations;
json["max_retry_attempts"] = profile.max_retry_attempts; json["max_retry_attempts"] = profile.max_retry_attempts;
json["tags"] = profile.tags; json["tags"] = profile.tags;
json["created_at"] = absl::FormatTime(absl::RFC3339_full, profile.created_at, absl::UTCTimeZone()); json["created_at"] = absl::FormatTime(absl::RFC3339_full, profile.created_at,
json["modified_at"] = absl::FormatTime(absl::RFC3339_full, profile.modified_at, absl::UTCTimeZone()); absl::UTCTimeZone());
json["modified_at"] = absl::FormatTime(
absl::RFC3339_full, profile.modified_at, absl::UTCTimeZone());
return json.dump(2); return json.dump(2);
#else #else
@@ -1183,7 +1277,8 @@ std::string AgentEditor::ProfileToJson(const BotProfile& profile) const {
#endif #endif
} }
absl::StatusOr<AgentEditor::BotProfile> AgentEditor::JsonToProfile(const std::string& json_str) const { absl::StatusOr<AgentEditor::BotProfile> AgentEditor::JsonToProfile(
const std::string& json_str) const {
#if defined(YAZE_WITH_JSON) #if defined(YAZE_WITH_JSON)
try { try {
nlohmann::json json = nlohmann::json::parse(json_str); nlohmann::json json = nlohmann::json::parse(json_str);
@@ -1209,21 +1304,26 @@ absl::StatusOr<AgentEditor::BotProfile> AgentEditor::JsonToProfile(const std::st
if (json.contains("created_at")) { if (json.contains("created_at")) {
absl::Time created; absl::Time created;
if (absl::ParseTime(absl::RFC3339_full, json["created_at"].get<std::string>(), &created, nullptr)) { if (absl::ParseTime(absl::RFC3339_full,
json["created_at"].get<std::string>(), &created,
nullptr)) {
profile.created_at = created; profile.created_at = created;
} }
} }
if (json.contains("modified_at")) { if (json.contains("modified_at")) {
absl::Time modified; absl::Time modified;
if (absl::ParseTime(absl::RFC3339_full, json["modified_at"].get<std::string>(), &modified, nullptr)) { if (absl::ParseTime(absl::RFC3339_full,
json["modified_at"].get<std::string>(), &modified,
nullptr)) {
profile.modified_at = modified; profile.modified_at = modified;
} }
} }
return profile; return profile;
} catch (const std::exception& e) { } catch (const std::exception& e) {
return absl::InternalError(absl::StrFormat("Failed to parse profile JSON: %s", e.what())); return absl::InternalError(
absl::StrFormat("Failed to parse profile JSON: %s", e.what()));
} }
#else #else
return absl::UnimplementedError("JSON support required"); return absl::UnimplementedError("JSON support required");
@@ -1277,7 +1377,8 @@ absl::StatusOr<AgentEditor::SessionInfo> AgentEditor::HostSession(
current_mode_ = mode; current_mode_ = mode;
if (mode == CollaborationMode::kLocal) { if (mode == CollaborationMode::kLocal) {
ASSIGN_OR_RETURN(auto session, local_coordinator_->HostSession(session_name)); ASSIGN_OR_RETURN(auto session,
local_coordinator_->HostSession(session_name));
SessionInfo info; SessionInfo info;
info.session_id = session.session_id; info.session_id = session.session_id;
@@ -1349,7 +1450,8 @@ absl::StatusOr<AgentEditor::SessionInfo> AgentEditor::JoinSession(
current_mode_ = mode; current_mode_ = mode;
if (mode == CollaborationMode::kLocal) { if (mode == CollaborationMode::kLocal) {
ASSIGN_OR_RETURN(auto session, local_coordinator_->JoinSession(session_code)); ASSIGN_OR_RETURN(auto session,
local_coordinator_->JoinSession(session_code));
SessionInfo info; SessionInfo info;
info.session_id = session.session_id; info.session_id = session.session_id;
@@ -1551,10 +1653,11 @@ void AgentEditor::SetupChatWidgetCallbacks() {
AgentChatWidget::CollaborationCallbacks collab_callbacks; AgentChatWidget::CollaborationCallbacks collab_callbacks;
collab_callbacks.host_session = collab_callbacks.host_session = [this](const std::string& session_name)
[this](const std::string& session_name) -> absl::StatusOr<
-> absl::StatusOr<AgentChatWidget::CollaborationCallbacks::SessionContext> { AgentChatWidget::CollaborationCallbacks::SessionContext> {
ASSIGN_OR_RETURN(auto session, this->HostSession(session_name, current_mode_)); ASSIGN_OR_RETURN(auto session,
this->HostSession(session_name, current_mode_));
AgentChatWidget::CollaborationCallbacks::SessionContext context; AgentChatWidget::CollaborationCallbacks::SessionContext context;
context.session_id = session.session_id; context.session_id = session.session_id;
@@ -1563,10 +1666,11 @@ void AgentEditor::SetupChatWidgetCallbacks() {
return context; return context;
}; };
collab_callbacks.join_session = collab_callbacks.join_session = [this](const std::string& session_code)
[this](const std::string& session_code) -> absl::StatusOr<
-> absl::StatusOr<AgentChatWidget::CollaborationCallbacks::SessionContext> { AgentChatWidget::CollaborationCallbacks::SessionContext> {
ASSIGN_OR_RETURN(auto session, this->JoinSession(session_code, current_mode_)); ASSIGN_OR_RETURN(auto session,
this->JoinSession(session_code, current_mode_));
AgentChatWidget::CollaborationCallbacks::SessionContext context; AgentChatWidget::CollaborationCallbacks::SessionContext context;
context.session_id = session.session_id; context.session_id = session.session_id;
@@ -1580,7 +1684,8 @@ void AgentEditor::SetupChatWidgetCallbacks() {
}; };
collab_callbacks.refresh_session = collab_callbacks.refresh_session =
[this]() -> absl::StatusOr<AgentChatWidget::CollaborationCallbacks::SessionContext> { [this]() -> absl::StatusOr<
AgentChatWidget::CollaborationCallbacks::SessionContext> {
ASSIGN_OR_RETURN(auto session, this->RefreshSession()); ASSIGN_OR_RETURN(auto session, this->RefreshSession());
AgentChatWidget::CollaborationCallbacks::SessionContext context; AgentChatWidget::CollaborationCallbacks::SessionContext context;

View File

@@ -1,89 +0,0 @@
// Application entry point - separated from C API implementation
#include "yaze.h"
#include <algorithm>
#include <iostream>
#include <memory>
#include <set>
#include <sstream>
#include <string>
#include "app/core/controller.h"
#include "app/core/platform/app_delegate.h"
#include "util/flag.h"
#include "util/log.h"
#include "yaze_config.h"
DEFINE_FLAG(std::string, rom_file, "",
"Path to the ROM file to load. "
"If not specified, the app will run without a ROM.");
DEFINE_FLAG(
std::string, log_level, "info",
"Minimum log level to output (e.g., debug, info, warn, error, fatal).");
DEFINE_FLAG(std::string, log_file, "",
"Path to the log file. If empty, logs to stderr.");
DEFINE_FLAG(std::string, log_categories, "",
"Comma-separated list of log categories to enable.");
int yaze_app_main(int argc, char** argv) {
yaze::util::FlagParser parser(yaze::util::global_flag_registry());
RETURN_IF_EXCEPTION(parser.Parse(argc, argv));
// --- Configure Logging System ---
auto string_to_log_level = [](const std::string& s) {
std::string upper_s;
std::transform(s.begin(), s.end(), std::back_inserter(upper_s),
::toupper);
if (upper_s == "YAZE_DEBUG") return yaze::util::LogLevel::YAZE_DEBUG;
if (upper_s == "INFO") return yaze::util::LogLevel::INFO;
if (upper_s == "WARN" || upper_s == "WARNING")
return yaze::util::LogLevel::WARNING;
if (upper_s == "ERROR") return yaze::util::LogLevel::ERROR;
if (upper_s == "FATAL") return yaze::util::LogLevel::FATAL;
return yaze::util::LogLevel::INFO; // Default
};
auto split_categories = [](const std::string& s) {
std::set<std::string> result;
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, ',')) {
if (!item.empty()) {
result.insert(item);
}
}
return result;
};
yaze::util::LogManager::instance().configure(
string_to_log_level(FLAGS_log_level->Get()), FLAGS_log_file->Get(),
split_categories(FLAGS_log_categories->Get()));
LOG_INFO("App", "Yaze starting up...");
LOG_INFO("App", "Version: %s", YAZE_VERSION_STRING);
std::string rom_filename = "";
if (!FLAGS_rom_file->Get().empty()) {
rom_filename = FLAGS_rom_file->Get();
LOG_INFO("App", "Loading ROM file: %s", rom_filename);
}
#ifdef __APPLE__
return yaze_run_cocoa_app_delegate(rom_filename.c_str());
#endif
auto controller = std::make_unique<yaze::core::Controller>();
EXIT_IF_ERROR(controller->OnEntry(rom_filename))
while (controller->IsActive()) {
controller->OnInput();
if (auto status = controller->OnLoad(); !status.ok()) {
LOG_ERROR("App", "Controller OnLoad failed: %s", status.message());
break;
}
controller->DoRender();
}
controller->OnExit();
LOG_INFO("App", "Yaze shutting down.");
return EXIT_SUCCESS;
}

View File

@@ -120,11 +120,23 @@ absl::StatusOr<std::string> PromptBuilder::ResolveCataloguePath(
for (const auto& candidate : search_paths) { for (const auto& candidate : search_paths) {
fs::path resolved = candidate; fs::path resolved = candidate;
if (resolved.is_relative()) { if (resolved.is_relative()) {
try {
resolved = fs::absolute(resolved); 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)) { if (fs::exists(resolved)) {
return resolved.string(); return resolved.string();
} }
} catch (const std::exception& e) {
// If checking existence fails, just continue to next path
continue;
}
} }
return absl::NotFoundError( return absl::NotFoundError(