7#include "absl/strings/str_format.h"
8#include "absl/time/time.h"
14#include "imgui/imgui.h"
17#ifdef YAZE_ENABLE_POLICY_FRAMEWORK
48 float list_height = ImGui::GetContentRegionAvail().y * 0.4f;
50 ImGui::BeginChild(
"ProposalListEmbed", ImVec2(0, list_height),
true);
56 ImGui::BeginChild(
"ProposalDetailEmbed", ImVec2(0, 0),
true);
67 ImGuiIO& io = ImGui::GetIO();
68 ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x -
drawer_width_, 0),
70 ImGui::SetNextWindowSize(ImVec2(
drawer_width_, io.DisplaySize.y),
73 ImGuiWindowFlags flags = ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize |
74 ImGuiWindowFlags_NoCollapse;
76 if (ImGui::Begin(
"Agent Proposals", &
visible_, flags)) {
95 float list_height = ImGui::GetContentRegionAvail().y * 0.4f;
97 ImGui::BeginChild(
"ProposalList", ImVec2(0, list_height),
true);
103 ImGui::BeginChild(
"ProposalDetail", ImVec2(0, 0),
true);
112 ImGui::OpenPopup(
"Confirm Action");
116 if (ImGui::BeginPopupModal(
"Confirm Action",
nullptr,
117 ImGuiWindowFlags_AlwaysAutoResize)) {
118 ImGui::Text(
"Are you sure you want to %s this proposal?",
122 if (ImGui::Button(
"Yes", ImVec2(120, 0))) {
130 ImGui::CloseCurrentPopup();
134 if (ImGui::Button(
"No", ImVec2(120, 0))) {
135 ImGui::CloseCurrentPopup();
140#ifdef YAZE_ENABLE_POLICY_FRAMEWORK
143 ImGui::OpenPopup(
"Override Policy");
147 if (ImGui::BeginPopupModal(
"Override Policy",
nullptr,
148 ImGuiWindowFlags_AlwaysAutoResize)) {
152 ImGui::TextWrapped(
"This proposal has policy warnings.");
153 ImGui::TextWrapped(
"Do you want to override and accept anyway?");
156 "Note: This action will be logged.");
159 if (ImGui::Button(
"Override and Accept", ImVec2(150, 0))) {
162 ImGui::CloseCurrentPopup();
165 if (ImGui::Button(
"Cancel", ImVec2(150, 0))) {
166 ImGui::CloseCurrentPopup();
175 ImGui::TextWrapped(
"No proposals found.");
176 ImGui::TextWrapped(
"Run CLI command: z3ed agent run --prompt \"...\"");
180 ImGuiTableFlags flags =
181 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY;
183 if (ImGui::BeginTable(
"ProposalsTable", 3, flags)) {
184 ImGui::TableSetupColumn(
"ID", ImGuiTableColumnFlags_WidthFixed, 60.0f);
185 ImGui::TableSetupColumn(
"Status", ImGuiTableColumnFlags_WidthFixed, 80.0f);
186 ImGui::TableSetupColumn(
"Prompt", ImGuiTableColumnFlags_WidthStretch);
187 ImGui::TableSetupScrollFreeze(0, 1);
188 ImGui::TableHeadersRow();
191 ImGui::TableNextRow();
194 ImGui::TableSetColumnIndex(0);
196 if (ImGui::Selectable(proposal.id.c_str(), is_selected,
197 ImGuiSelectableFlags_SpanAllColumns)) {
202 ImGui::TableSetColumnIndex(1);
203 switch (proposal.status) {
218 ImGui::TableSetColumnIndex(2);
219 std::string truncated = proposal.prompt;
220 if (truncated.length() > 30) {
221 truncated = truncated.substr(0, 27) +
"...";
223 ImGui::TextWrapped(
"%s", truncated.c_str());
237 if (ImGui::CollapsingHeader(
"Metadata", ImGuiTreeNodeFlags_DefaultOpen)) {
238 ImGui::Text(
"ID: %s", p.id.c_str());
239 ImGui::Text(
"Sandbox: %s", p.sandbox_id.c_str());
240 ImGui::Text(
"Created: %s", absl::FormatTime(p.created_at).c_str());
241 if (p.reviewed_at.has_value()) {
242 ImGui::Text(
"Reviewed: %s", absl::FormatTime(*p.reviewed_at).c_str());
244 ImGui::Text(
"Commands: %d", p.commands_executed);
245 ImGui::Text(
"Bytes Changed: %d", p.bytes_changed);
247 ImGui::TextWrapped(
"Prompt: %s", p.prompt.c_str());
248 ImGui::TextWrapped(
"Description: %s", p.description.c_str());
252 if (ImGui::CollapsingHeader(
"Diff", ImGuiTreeNodeFlags_DefaultOpen)) {
253 if (
diff_content_.empty() && std::filesystem::exists(p.diff_path)) {
254 std::ifstream diff_file(p.diff_path);
255 if (diff_file.is_open()) {
256 std::stringstream buffer;
257 buffer << diff_file.rdbuf();
263 ImGui::BeginChild(
"DiffContent", ImVec2(0, 150),
true,
264 ImGuiWindowFlags_HorizontalScrollbar);
268 ImGui::TextWrapped(
"No diff available");
273 if (ImGui::CollapsingHeader(
"Execution Log")) {
274 if (
log_content_.empty() && std::filesystem::exists(p.log_path)) {
275 std::ifstream log_file(p.log_path);
276 if (log_file.is_open()) {
277 std::stringstream buffer;
280 while (std::getline(log_file, line) &&
282 buffer << line <<
"\n";
286 buffer <<
"... (truncated, see " << p.log_path.string() <<
")\n";
293 ImGui::BeginChild(
"LogContent", ImVec2(0, 150),
true,
294 ImGuiWindowFlags_HorizontalScrollbar);
298 ImGui::TextWrapped(
"No log available");
303#ifdef YAZE_ENABLE_POLICY_FRAMEWORK
313 const char* filter_labels[] = {
"All",
"Pending",
"Accepted",
"Rejected"};
316 ImGui::SetNextItemWidth(120.0f);
317 if (ImGui::Combo(
"Filter", ¤t_filter, filter_labels, 4)) {
324#ifdef YAZE_ENABLE_POLICY_FRAMEWORK
335 if (ImGui::CollapsingHeader(
"Policy Status",
336 ImGuiTreeNodeFlags_DefaultOpen)) {
339 if (!policy_eval.IsEnabled()) {
343 "Create .yaze/policies/agent.yaml to enable policy evaluation");
348 auto policy_result = policy_eval.EvaluateProposal(p.id);
350 if (!policy_result.ok()) {
353 ImGui::TextWrapped(
"%s", policy_result.status().message().data());
357 const auto& result = policy_result.value();
360 if (result.is_clean()) {
363 }
else if (result.passed) {
374 if (!result.critical_violations.empty()) {
377 for (
const auto& violation : result.critical_violations) {
379 ImGui::TextWrapped(
"%s: %s", violation.policy_name.c_str(),
380 violation.message.c_str());
381 if (!violation.details.empty()) {
384 violation.details.c_str());
392 if (!result.warnings.empty()) {
394 for (
const auto& violation : result.warnings) {
396 ImGui::TextWrapped(
"%s: %s", violation.policy_name.c_str(),
397 violation.message.c_str());
398 if (!violation.details.empty()) {
401 violation.details.c_str());
409 if (!result.info.empty()) {
411 for (
const auto& violation : result.info) {
413 ImGui::TextWrapped(
"%s: %s", violation.policy_name.c_str(),
414 violation.message.c_str());
429 bool can_accept =
true;
430 bool needs_override =
false;
432#ifdef YAZE_ENABLE_POLICY_FRAMEWORK
435 if (policy_eval.IsEnabled()) {
436 auto policy_result = policy_eval.EvaluateProposal(p.id);
437 if (policy_result.ok()) {
438 const auto& result = policy_result.value();
439 can_accept = !result.has_critical_violations();
440 needs_override = result.can_accept_with_override();
449 ImGui::BeginDisabled();
453 if (needs_override) {
466 ImGui::EndDisabled();
498 std::optional<cli::ProposalRegistry::ProposalStatus> filter;
510 filter = std::nullopt;
543 if (p.id == proposal_id) {
555 auto proposal_or = registry.GetProposal(proposal_id);
556 if (!proposal_or.ok()) {
557 return proposal_or.status();
560 const auto& proposal = *proposal_or;
564 return absl::FailedPreconditionError(
565 "No ROM loaded. Cannot merge proposal changes.");
570 auto sandboxes = sandbox_mgr.ListSandboxes();
572 std::filesystem::path sandbox_rom_path;
573 for (
const auto& sandbox : sandboxes) {
574 if (sandbox.id == proposal.sandbox_id) {
575 sandbox_rom_path = sandbox.rom_path;
580 if (sandbox_rom_path.empty()) {
581 return absl::NotFoundError(
582 absl::StrFormat(
"Sandbox ROM not found for proposal %s (sandbox: %s)",
583 proposal_id, proposal.sandbox_id));
588 if (!std::filesystem::exists(sandbox_rom_path, ec)) {
589 return absl::NotFoundError(absl::StrFormat(
590 "Sandbox ROM file does not exist: %s", sandbox_rom_path.string()));
595 auto load_status = sandbox_rom.LoadFromFile(sandbox_rom_path.string());
596 if (!load_status.ok()) {
597 return absl::InternalError(absl::StrFormat(
"Failed to load sandbox ROM: %s",
598 load_status.message()));
603 const auto& sandbox_data = sandbox_rom.vector();
605 if (!merge_status.ok()) {
606 return absl::InternalError(absl::StrFormat(
607 "Failed to merge sandbox ROM data: %s", merge_status.message()));
611 auto status = registry.UpdateStatus(
623 return absl::UnimplementedError(
"AI features disabled");
630 auto status = registry.UpdateStatus(
636 return absl::UnimplementedError(
"AI features disabled");
643 auto status = registry.RemoveProposal(proposal_id);
655 return absl::UnimplementedError(
"AI features disabled");
absl::Status WriteVector(int addr, std::vector< uint8_t > data)
static PolicyEvaluator & GetInstance()
static ProposalRegistry & Instance()
static RomSandboxManager & Instance()
absl::Status AcceptProposal(const std::string &proposal_id)
void DrawProposalDetail()
StatusFilter status_filter_
std::string selected_proposal_id_
absl::Status RejectProposal(const std::string &proposal_id)
bool show_confirm_dialog_
cli::ProposalRegistry::ProposalMetadata * selected_proposal_
std::string confirm_action_
absl::Status DeleteProposal(const std::string &proposal_id)
std::string diff_content_
void FocusProposal(const std::string &proposal_id)
std::vector< cli::ProposalRegistry::ProposalMetadata > proposals_
std::string confirm_proposal_id_
void SelectProposal(const std::string &proposal_id)
bool show_override_dialog_
#define ICON_MD_HOURGLASS_TOP
#define ICON_MD_CHECK_CIRCLE
ImVec4 GetDisabledColor()