feat: Add proposal executor for agent response handling and command execution

This commit is contained in:
scawful
2025-10-04 05:18:09 -04:00
parent 8deb2656d5
commit acada1bec5
5 changed files with 320 additions and 117 deletions

View File

@@ -3,17 +3,26 @@
#include <algorithm>
#include <cctype>
#include <iostream>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include "absl/flags/declare.h"
#include "absl/flags/flag.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/time/clock.h"
#include "app/rom.h"
#include "cli/service/agent/proposal_executor.h"
#include "cli/service/ai/service_factory.h"
#include "cli/util/terminal_colors.h"
#include "nlohmann/json.hpp"
ABSL_DECLARE_FLAG(std::string, ai_provider);
namespace yaze {
namespace cli {
namespace agent {
@@ -300,6 +309,47 @@ absl::StatusOr<ChatMessage> ConversationalAgentService::SendMessage(
continue;
}
std::optional<ProposalCreationResult> proposal_result;
absl::Status proposal_status = absl::OkStatus();
bool attempted_proposal = false;
if (!agent_response.commands.empty()) {
attempted_proposal = true;
if (rom_context_ == nullptr) {
proposal_status = absl::FailedPreconditionError(
"No ROM context available for proposal creation");
util::PrintWarning(
"Cannot create proposal because no ROM context is active.");
} else if (!rom_context_->is_loaded()) {
proposal_status = absl::FailedPreconditionError(
"ROM context is not loaded");
util::PrintWarning(
"Cannot create proposal because the ROM context is not loaded.");
} else {
ProposalCreationRequest request;
request.prompt = message;
request.response = &agent_response;
request.rom = rom_context_;
request.sandbox_label = "agent-chat";
request.ai_provider = absl::GetFlag(FLAGS_ai_provider);
auto creation_or = CreateProposalFromAgentResponse(request);
if (!creation_or.ok()) {
proposal_status = creation_or.status();
util::PrintError(absl::StrCat(
"Failed to create proposal: ", proposal_status.message()));
} else {
proposal_result = std::move(creation_or.value());
if (config_.verbose) {
util::PrintSuccess(absl::StrCat(
"Created proposal ", proposal_result->metadata.id,
" with ", proposal_result->change_count, " change(s)."));
}
}
}
}
std::string response_text = agent_response.text_response;
if (!agent_response.reasoning.empty()) {
if (!response_text.empty()) {
@@ -316,6 +366,30 @@ absl::StatusOr<ChatMessage> ConversationalAgentService::SendMessage(
response_text.append(absl::StrJoin(agent_response.commands, "\n"));
}
if (proposal_result.has_value()) {
const auto& metadata = proposal_result->metadata;
if (!response_text.empty()) {
response_text.append("\n\n");
}
response_text.append(absl::StrFormat(
"✅ Proposal %s ready with %d change%s (%d command%s).\n"
"Review it in the Proposal drawer or run `z3ed agent diff --proposal-id %s`.\n"
"Sandbox ROM: %s\nProposal JSON: %s",
metadata.id, proposal_result->change_count,
proposal_result->change_count == 1 ? "" : "s",
proposal_result->executed_commands,
proposal_result->executed_commands == 1 ? "" : "s",
metadata.id, metadata.sandbox_rom_path.string(),
proposal_result->proposal_json_path.string()));
} else if (attempted_proposal && !proposal_status.ok()) {
if (!response_text.empty()) {
response_text.append("\n\n");
}
response_text.append(absl::StrCat(
"⚠️ Failed to prepare a proposal automatically: ",
proposal_status.message()));
}
ChatMessage chat_response =
CreateMessage(ChatMessage::Sender::kAgent, response_text);
history_.push_back(chat_response);