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#ifndef YAZE_AI_RUNTIME_AVAILABLE
4
5#include "absl/status/status.h"
6
7namespace yaze::cli::agent {
8
9absl::StatusOr<ProposalCreationResult> CreateProposalFromAgentResponse(
11 return absl::FailedPreconditionError(
12 "AI runtime features are disabled in this build");
13}
14
15} // namespace yaze::cli::agent
16
17#else // YAZE_AI_RUNTIME_AVAILABLE
18
19#include <filesystem>
20#include <sstream>
21#include <utility>
22#include <vector>
23
24#include "absl/status/status.h"
25#include "absl/status/statusor.h"
26#include "absl/strings/str_cat.h"
27#include "absl/strings/str_format.h"
28#include "absl/strings/str_join.h"
29#include "rom/rom.h"
32#include "util/macro.h"
33
34namespace yaze {
35namespace cli {
36namespace agent {
37
38namespace {
39
40std::string InferProvider(const std::string& provider) {
41 if (!provider.empty()) {
42 return provider;
43 }
44 return "unknown";
45}
46
47bool IsExecutableCommand(absl::string_view command) {
48 return !command.empty() && command.front() != '#';
49}
50
51} // namespace
52
53absl::StatusOr<ProposalCreationResult> CreateProposalFromAgentResponse(
54 const ProposalCreationRequest& request) {
55 if (request.response == nullptr) {
56 return absl::InvalidArgumentError("Agent response is required");
57 }
58 if (request.rom == nullptr) {
59 return absl::InvalidArgumentError("ROM context is required");
60 }
61 if (!request.rom->is_loaded()) {
62 return absl::FailedPreconditionError(
63 "ROM must be loaded before creating proposals");
64 }
65 if (request.response->commands.empty()) {
66 return absl::InvalidArgumentError(
67 "Agent response did not contain any commands to execute");
68 }
69
71 *request.rom, request.sandbox_label);
72 if (!sandbox_or.ok()) {
73 return sandbox_or.status();
74 }
75 auto sandbox = sandbox_or.value();
76
77 Tile16ProposalGenerator generator;
78 ASSIGN_OR_RETURN(auto proposal,
79 generator.GenerateFromCommands(
80 request.prompt, request.response->commands,
81 InferProvider(request.ai_provider), request.rom));
82
83 Rom sandbox_rom;
84 RETURN_IF_ERROR(sandbox_rom.LoadFromFile(sandbox.rom_path.string()));
85
86 RETURN_IF_ERROR(generator.ApplyProposal(proposal, &sandbox_rom));
87
88 RETURN_IF_ERROR(sandbox_rom.SaveToFile({.save_new = false}));
89
90 auto& registry = ProposalRegistry::Instance();
91
92 int executed_commands = 0;
93 for (const auto& command : request.response->commands) {
94 if (IsExecutableCommand(command)) {
95 ++executed_commands;
96 }
97 }
98
99 std::string description = absl::StrFormat(
100 "Tile16 overworld edits (%d change%s)", proposal.changes.size(),
101 proposal.changes.size() == 1 ? "" : "s");
102
103 ASSIGN_OR_RETURN(auto metadata,
104 registry.CreateProposal(sandbox.id, sandbox.rom_path,
105 request.prompt, description));
106
107 proposal.id = metadata.id;
108
109 std::ostringstream diff_stream;
110 diff_stream << "Tile16 Proposal ID: " << metadata.id << "\n";
111 diff_stream << "Sandbox ID: " << sandbox.id << "\n";
112 diff_stream << "Sandbox ROM: " << sandbox.rom_path << "\n\n";
113 diff_stream << "Changes (" << proposal.changes.size() << "):\n";
114 for (const auto& change : proposal.changes) {
115 diff_stream << " - " << change.ToString() << "\n";
116 }
117
118 RETURN_IF_ERROR(registry.RecordDiff(metadata.id, diff_stream.str()));
119
120 RETURN_IF_ERROR(registry.AppendLog(metadata.id,
121 absl::StrCat("Prompt: ", request.prompt)));
122
123 if (!request.response->text_response.empty()) {
124 RETURN_IF_ERROR(registry.AppendLog(
125 metadata.id,
126 absl::StrCat("AI Response: ", request.response->text_response)));
127 }
128
129 if (!request.response->reasoning.empty()) {
130 RETURN_IF_ERROR(registry.AppendLog(
131 metadata.id, absl::StrCat("Reasoning: ", request.response->reasoning)));
132 }
133
134 if (!request.response->tool_calls.empty()) {
135 std::vector<std::string> call_summaries;
136 call_summaries.reserve(request.response->tool_calls.size());
137 for (const auto& tool_call : request.response->tool_calls) {
138 std::vector<std::string> args;
139 for (const auto& [key, value] : tool_call.args) {
140 args.push_back(absl::StrCat(key, "=", value));
141 }
142 call_summaries.push_back(absl::StrCat(tool_call.tool_name, "(",
143 absl::StrJoin(args, ", "), ")"));
144 }
145 RETURN_IF_ERROR(registry.AppendLog(
146 metadata.id, absl::StrCat("Tool Calls (", call_summaries.size(),
147 "): ", absl::StrJoin(call_summaries, "; "))));
148 }
149
150 for (const auto& command : request.response->commands) {
151 if (!IsExecutableCommand(command)) {
152 continue;
153 }
155 registry.AppendLog(metadata.id, absl::StrCat("Command: ", command)));
156 }
157
158 RETURN_IF_ERROR(registry.AppendLog(
159 metadata.id,
160 absl::StrCat("Sandbox ROM saved to ", sandbox.rom_path.string())));
161
162 RETURN_IF_ERROR(registry.UpdateCommandStats(metadata.id, executed_commands));
163 RETURN_IF_ERROR(registry.AppendLog(
164 metadata.id, absl::StrCat("Commands executed: ", executed_commands)));
165
166 std::filesystem::path proposal_dir = metadata.log_path.parent_path();
167 std::filesystem::path proposal_path = proposal_dir / "proposal.json";
168 RETURN_IF_ERROR(generator.SaveProposal(proposal, proposal_path.string()));
169
170 RETURN_IF_ERROR(registry.AppendLog(
171 metadata.id,
172 absl::StrCat("Saved proposal JSON to ", proposal_path.string())));
173
174 if (!request.ai_provider.empty()) {
175 RETURN_IF_ERROR(registry.AppendLog(
176 metadata.id, absl::StrCat("AI Provider: ", request.ai_provider)));
177 }
178
179 ASSIGN_OR_RETURN(auto refreshed_metadata, registry.GetProposal(metadata.id));
180
181 ProposalCreationResult result;
182 result.metadata = std::move(refreshed_metadata);
183 result.proposal_json_path = std::move(proposal_path);
184 result.executed_commands = executed_commands;
185 result.change_count = static_cast<int>(proposal.changes.size());
186 return result;
187}
188
189} // namespace agent
190} // namespace cli
191} // namespace yaze
192
193#endif // YAZE_AI_RUNTIME_AVAILABLE
static ProposalRegistry & Instance()
absl::StatusOr< SandboxMetadata > CreateSandbox(Rom &rom, absl::string_view description)
static RomSandboxManager & Instance()
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition macro.h:62
absl::StatusOr< ProposalCreationResult > CreateProposalFromAgentResponse(const ProposalCreationRequest &)
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22