yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
proposal_executor.cc
Go to the documentation of this file.
2
3#include <filesystem>
4#include <sstream>
5#include <utility>
6#include <vector>
7
8#include "absl/status/status.h"
9#include "absl/status/statusor.h"
10#include "absl/strings/str_cat.h"
11#include "absl/strings/str_format.h"
12#include "absl/strings/str_join.h"
13#include "app/rom.h"
16#include "util/macro.h"
17
18namespace yaze {
19namespace cli {
20namespace agent {
21
22namespace {
23
24std::string InferProvider(const std::string& provider) {
25 if (!provider.empty()) {
26 return provider;
27 }
28 return "unknown";
29}
30
31bool IsExecutableCommand(absl::string_view command) {
32 return !command.empty() && command.front() != '#';
33}
34
35} // namespace
36
37absl::StatusOr<ProposalCreationResult> CreateProposalFromAgentResponse(
38 const ProposalCreationRequest& request) {
39 if (request.response == nullptr) {
40 return absl::InvalidArgumentError("Agent response is required");
41 }
42 if (request.rom == nullptr) {
43 return absl::InvalidArgumentError("ROM context is required");
44 }
45 if (!request.rom->is_loaded()) {
46 return absl::FailedPreconditionError(
47 "ROM must be loaded before creating proposals");
48 }
49 if (request.response->commands.empty()) {
50 return absl::InvalidArgumentError(
51 "Agent response did not contain any commands to execute");
52 }
53
54 auto sandbox_or =
56 request.sandbox_label);
57 if (!sandbox_or.ok()) {
58 return sandbox_or.status();
59 }
60 auto sandbox = sandbox_or.value();
61
63 ASSIGN_OR_RETURN(auto proposal,
64 generator.GenerateFromCommands(
65 request.prompt, request.response->commands,
66 InferProvider(request.ai_provider), request.rom));
67
68 Rom sandbox_rom;
70 sandbox_rom.LoadFromFile(sandbox.rom_path.string()));
71
72 RETURN_IF_ERROR(generator.ApplyProposal(proposal, &sandbox_rom));
73
74 RETURN_IF_ERROR(sandbox_rom.SaveToFile({.save_new = false}));
75
76 auto& registry = ProposalRegistry::Instance();
77
78 int executed_commands = 0;
79 for (const auto& command : request.response->commands) {
80 if (IsExecutableCommand(command)) {
81 ++executed_commands;
82 }
83 }
84
85 std::string description = absl::StrFormat(
86 "Tile16 overworld edits (%d change%s)", proposal.changes.size(),
87 proposal.changes.size() == 1 ? "" : "s");
88
89 ASSIGN_OR_RETURN(auto metadata,
90 registry.CreateProposal(sandbox.id, sandbox.rom_path,
91 request.prompt, description));
92
93 proposal.id = metadata.id;
94
95 std::ostringstream diff_stream;
96 diff_stream << "Tile16 Proposal ID: " << metadata.id << "\n";
97 diff_stream << "Sandbox ID: " << sandbox.id << "\n";
98 diff_stream << "Sandbox ROM: " << sandbox.rom_path << "\n\n";
99 diff_stream << "Changes (" << proposal.changes.size() << "):\n";
100 for (const auto& change : proposal.changes) {
101 diff_stream << " - " << change.ToString() << "\n";
102 }
103
104 RETURN_IF_ERROR(registry.RecordDiff(metadata.id, diff_stream.str()));
105
106 RETURN_IF_ERROR(registry.AppendLog(
107 metadata.id, absl::StrCat("Prompt: ", request.prompt)));
108
109 if (!request.response->text_response.empty()) {
110 RETURN_IF_ERROR(registry.AppendLog(
111 metadata.id,
112 absl::StrCat("AI Response: ", request.response->text_response)));
113 }
114
115 if (!request.response->reasoning.empty()) {
116 RETURN_IF_ERROR(registry.AppendLog(
117 metadata.id,
118 absl::StrCat("Reasoning: ", request.response->reasoning)));
119 }
120
121 if (!request.response->tool_calls.empty()) {
122 std::vector<std::string> call_summaries;
123 call_summaries.reserve(request.response->tool_calls.size());
124 for (const auto& tool_call : request.response->tool_calls) {
125 std::vector<std::string> args;
126 for (const auto& [key, value] : tool_call.args) {
127 args.push_back(absl::StrCat(key, "=", value));
128 }
129 call_summaries.push_back(absl::StrCat(
130 tool_call.tool_name, "(", absl::StrJoin(args, ", "), ")"));
131 }
132 RETURN_IF_ERROR(registry.AppendLog(
133 metadata.id,
134 absl::StrCat("Tool Calls (", call_summaries.size(), "): ",
135 absl::StrJoin(call_summaries, "; "))));
136 }
137
138 for (const auto& command : request.response->commands) {
139 if (!IsExecutableCommand(command)) {
140 continue;
141 }
142 RETURN_IF_ERROR(registry.AppendLog(
143 metadata.id, absl::StrCat("Command: ", command)));
144 }
145
146 RETURN_IF_ERROR(registry.AppendLog(
147 metadata.id,
148 absl::StrCat("Sandbox ROM saved to ", sandbox.rom_path.string())));
149
151 registry.UpdateCommandStats(metadata.id, executed_commands));
152 RETURN_IF_ERROR(registry.AppendLog(
153 metadata.id,
154 absl::StrCat("Commands executed: ", executed_commands)));
155
156 std::filesystem::path proposal_dir = metadata.log_path.parent_path();
157 std::filesystem::path proposal_path = proposal_dir / "proposal.json";
158 RETURN_IF_ERROR(generator.SaveProposal(proposal, proposal_path.string()));
159
160 RETURN_IF_ERROR(registry.AppendLog(
161 metadata.id,
162 absl::StrCat("Saved proposal JSON to ", proposal_path.string())));
163
164 if (!request.ai_provider.empty()) {
165 RETURN_IF_ERROR(registry.AppendLog(
166 metadata.id, absl::StrCat("AI Provider: ", request.ai_provider)));
167 }
168
169 ASSIGN_OR_RETURN(auto refreshed_metadata,
170 registry.GetProposal(metadata.id));
171
173 result.metadata = std::move(refreshed_metadata);
174 result.proposal_json_path = std::move(proposal_path);
175 result.executed_commands = executed_commands;
176 result.change_count = static_cast<int>(proposal.changes.size());
177 return result;
178}
179
180} // namespace agent
181} // namespace cli
182} // namespace yaze
The Rom class is used to load, save, and modify Rom data.
Definition rom.h:71
absl::Status LoadFromFile(const std::string &filename, bool z3_load=true)
Definition rom.cc:289
absl::Status SaveToFile(const SaveSettings &settings)
Definition rom.cc:536
bool is_loaded() const
Definition rom.h:197
static ProposalRegistry & Instance()
absl::StatusOr< SandboxMetadata > CreateSandbox(Rom &rom, absl::string_view description)
static RomSandboxManager & Instance()
Generates and manages tile16 editing proposals.
absl::StatusOr< Tile16Proposal > GenerateFromCommands(const std::string &prompt, const std::vector< std::string > &commands, const std::string &ai_service, Rom *rom)
Generate a tile16 proposal from an AI-generated command list.
absl::Status ApplyProposal(const Tile16Proposal &proposal, Rom *rom)
Apply a proposal to a ROM (typically a sandbox).
absl::Status SaveProposal(const Tile16Proposal &proposal, const std::string &path)
Save a proposal to a JSON file for later review.
#define RETURN_IF_ERROR(expression)
Definition macro.h:53
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition macro.h:61
std::string InferProvider(const std::string &provider)
absl::StatusOr< ProposalCreationResult > CreateProposalFromAgentResponse(const ProposalCreationRequest &request)
Main namespace for the application.
std::vector< std::string > commands
Definition common.h:26
std::string reasoning
Definition common.h:29
std::vector< ToolCall > tool_calls
Definition common.h:23
std::string text_response
Definition common.h:20
ProposalRegistry::ProposalMetadata metadata