feat: Implement advanced routing system for agent tool responses
- Introduced AdvancedRouter class for routing hex analysis, map editing, and palette analysis responses. - Added methods for generating GUI automation scripts and synthesizing multi-tool responses. - Implemented knowledge modules for agent pretraining, covering ROM structure, hex analysis patterns, and tool usage examples. - Enhanced data handling with structured responses, including summaries, detailed data, and next steps for user guidance. - Refactored project build process to utilize std::filesystem for cross-platform patch application.
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
#include "cli/z3ed.h"
|
#include "cli/z3ed.h"
|
||||||
#include "util/file_util.h"
|
#include "util/file_util.h"
|
||||||
#include "util/bps.h"
|
#include "util/bps.h"
|
||||||
|
#include <filesystem>
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -40,17 +41,21 @@ absl::Status ProjectBuild::Run(const std::vector<std::string>& arg_vec) {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
// Apply BPS patches - cross-platform with std::filesystem
|
||||||
return absl::UnimplementedError(
|
namespace fs = std::filesystem;
|
||||||
"Project build with patches is not implemented on Windows yet.");
|
std::vector<std::string> bps_files;
|
||||||
#else
|
|
||||||
|
try {
|
||||||
// Apply BPS patches
|
for (const auto& entry : fs::directory_iterator(project.patches_folder)) {
|
||||||
glob_t glob_result;
|
if (entry.path().extension() == ".bps") {
|
||||||
std::string pattern = project.patches_folder + "/*.bps";
|
bps_files.push_back(entry.path().string());
|
||||||
glob(pattern.c_str(), GLOB_TILDE, NULL, &glob_result);
|
}
|
||||||
for (unsigned int i = 0; i < glob_result.gl_pathc; ++i) {
|
}
|
||||||
std::string patch_file = glob_result.gl_pathv[i];
|
} catch (const fs::filesystem_error& e) {
|
||||||
|
// Patches folder doesn't exist or not accessible
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& patch_file : bps_files) {
|
||||||
std::vector<uint8_t> patch_data;
|
std::vector<uint8_t> patch_data;
|
||||||
auto patch_contents = util::LoadFile(patch_file);
|
auto patch_contents = util::LoadFile(patch_file);
|
||||||
std::copy(patch_contents.begin(), patch_contents.end(),
|
std::copy(patch_contents.begin(), patch_contents.end(),
|
||||||
@@ -60,13 +65,21 @@ absl::Status ProjectBuild::Run(const std::vector<std::string>& arg_vec) {
|
|||||||
rom.LoadFromData(patched_rom);
|
rom.LoadFromData(patched_rom);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run asar on assembly files
|
// Run asar on assembly files - cross-platform
|
||||||
glob_t glob_result_asm;
|
std::vector<std::string> asm_files;
|
||||||
std::string pattern_asm = project.patches_folder + "/*.asm";
|
try {
|
||||||
glob(pattern_asm.c_str(), GLOB_TILDE, NULL, &glob_result_asm);
|
for (const auto& entry : fs::directory_iterator(project.patches_folder)) {
|
||||||
for (unsigned int i = 0; i < glob_result_asm.gl_pathc; ++i) {
|
if (entry.path().extension() == ".asm") {
|
||||||
|
asm_files.push_back(entry.path().string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const fs::filesystem_error& e) {
|
||||||
|
// No asm files
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& asm_file : asm_files) {
|
||||||
AsarPatch asar_patch;
|
AsarPatch asar_patch;
|
||||||
auto status = asar_patch.Run({glob_result_asm.gl_pathv[i]});
|
auto status = asar_patch.Run({asm_file});
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -82,7 +95,6 @@ absl::Status ProjectBuild::Run(const std::vector<std::string>& arg_vec) {
|
|||||||
std::cout << " Output ROM: " << output_file << std::endl;
|
std::cout << " Output ROM: " << output_file << std::endl;
|
||||||
|
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace cli
|
} // namespace cli
|
||||||
|
|||||||
208
src/cli/service/agent/advanced_routing.cc
Normal file
208
src/cli/service/agent/advanced_routing.cc
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
#include "cli/service/agent/advanced_routing.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
#include "absl/strings/str_format.h"
|
||||||
|
#include "absl/strings/str_join.h"
|
||||||
|
|
||||||
|
namespace yaze {
|
||||||
|
namespace cli {
|
||||||
|
namespace agent {
|
||||||
|
|
||||||
|
AdvancedRouter::RoutedResponse AdvancedRouter::RouteHexAnalysis(
|
||||||
|
const std::vector<uint8_t>& data,
|
||||||
|
uint32_t address,
|
||||||
|
const RouteContext& ctx) {
|
||||||
|
|
||||||
|
RoutedResponse response;
|
||||||
|
|
||||||
|
// Infer data type
|
||||||
|
std::string data_type = InferDataType(data);
|
||||||
|
auto patterns = ExtractPatterns(data);
|
||||||
|
|
||||||
|
// Summary for user
|
||||||
|
response.summary = absl::StrFormat(
|
||||||
|
"Address 0x%06X contains %s (%zu bytes)",
|
||||||
|
address, data_type, data.size());
|
||||||
|
|
||||||
|
// Detailed data for agent with structure hints
|
||||||
|
std::ostringstream detailed;
|
||||||
|
detailed << absl::StrFormat("Raw hex at 0x%06X:\n", address);
|
||||||
|
for (size_t i = 0; i < data.size(); i += 16) {
|
||||||
|
detailed << absl::StrFormat("%06X: ", address + i);
|
||||||
|
for (size_t j = i; j < std::min(i + 16, data.size()); ++j) {
|
||||||
|
detailed << absl::StrFormat("%02X ", data[j]);
|
||||||
|
}
|
||||||
|
detailed << " | ";
|
||||||
|
for (size_t j = i; j < std::min(i + 16, data.size()); ++j) {
|
||||||
|
char c = data[j];
|
||||||
|
detailed << (isprint(c) ? c : '.');
|
||||||
|
}
|
||||||
|
detailed << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!patterns.empty()) {
|
||||||
|
detailed << "\nDetected patterns:\n";
|
||||||
|
for (const auto& pattern : patterns) {
|
||||||
|
detailed << "- " << pattern << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.detailed_data = detailed.str();
|
||||||
|
|
||||||
|
// Next steps based on data type
|
||||||
|
if (data_type.find("sprite") != std::string::npos) {
|
||||||
|
response.next_steps = "Use resource-list --type=sprite to identify sprite IDs";
|
||||||
|
} else if (data_type.find("tile") != std::string::npos) {
|
||||||
|
response.next_steps = "Use overworld-find-tile to see where this tile appears";
|
||||||
|
} else if (data_type.find("palette") != std::string::npos) {
|
||||||
|
response.next_steps = "Use palette-get-colors to see full palette";
|
||||||
|
} else {
|
||||||
|
response.next_steps = "Use hex-search to find similar patterns in ROM";
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvancedRouter::RoutedResponse AdvancedRouter::RouteMapEdit(
|
||||||
|
const std::string& edit_intent,
|
||||||
|
const RouteContext& ctx) {
|
||||||
|
|
||||||
|
RoutedResponse response;
|
||||||
|
|
||||||
|
// Parse intent and generate action sequence
|
||||||
|
response.summary = "Preparing map edit operation";
|
||||||
|
response.needs_approval = true;
|
||||||
|
|
||||||
|
// Generate GUI automation steps
|
||||||
|
response.gui_actions = {
|
||||||
|
"Click(\"Overworld Editor\")",
|
||||||
|
"Wait(500)",
|
||||||
|
"Click(canvas, x, y)",
|
||||||
|
"SelectTile(tile_id)",
|
||||||
|
"Click(target_x, target_y)",
|
||||||
|
"Wait(100)",
|
||||||
|
"Screenshot(\"after_edit.png\")",
|
||||||
|
};
|
||||||
|
|
||||||
|
response.detailed_data = GenerateGUIScript(response.gui_actions);
|
||||||
|
response.next_steps = "Review proposed changes, then approve or modify";
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvancedRouter::RoutedResponse AdvancedRouter::RoutePaletteAnalysis(
|
||||||
|
const std::vector<uint16_t>& colors,
|
||||||
|
const RouteContext& ctx) {
|
||||||
|
|
||||||
|
RoutedResponse response;
|
||||||
|
|
||||||
|
// Analyze color relationships
|
||||||
|
int unique_colors = 0;
|
||||||
|
std::map<uint16_t, int> color_counts;
|
||||||
|
for (uint16_t c : colors) {
|
||||||
|
color_counts[c]++;
|
||||||
|
}
|
||||||
|
unique_colors = color_counts.size();
|
||||||
|
|
||||||
|
response.summary = absl::StrFormat(
|
||||||
|
"Palette has %zu colors (%d unique)",
|
||||||
|
colors.size(), unique_colors);
|
||||||
|
|
||||||
|
// Detailed breakdown
|
||||||
|
std::ostringstream detailed;
|
||||||
|
detailed << "Color breakdown:\n";
|
||||||
|
for (size_t i = 0; i < colors.size(); ++i) {
|
||||||
|
uint16_t snes = colors[i];
|
||||||
|
uint8_t r = (snes & 0x1F) << 3;
|
||||||
|
uint8_t g = ((snes >> 5) & 0x1F) << 3;
|
||||||
|
uint8_t b = ((snes >> 10) & 0x1F) << 3;
|
||||||
|
detailed << absl::StrFormat(" [%zu] $%04X = #%02X%02X%02X\n", i, snes, r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (color_counts.size() < colors.size()) {
|
||||||
|
detailed << "\nDuplicates found - optimization possible\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
response.detailed_data = detailed.str();
|
||||||
|
response.next_steps = "Use palette-set-color to modify colors";
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvancedRouter::RoutedResponse AdvancedRouter::SynthesizeMultiToolResponse(
|
||||||
|
const std::vector<std::string>& tool_results,
|
||||||
|
const RouteContext& ctx) {
|
||||||
|
|
||||||
|
RoutedResponse response;
|
||||||
|
|
||||||
|
// Combine results intelligently
|
||||||
|
response.summary = absl::StrFormat("Analyzed %zu data sources", tool_results.size());
|
||||||
|
response.detailed_data = absl::StrJoin(tool_results, "\n---\n");
|
||||||
|
|
||||||
|
// Generate insights
|
||||||
|
response.next_steps = "Analysis complete. " + ctx.user_intent;
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AdvancedRouter::GenerateGUIScript(
|
||||||
|
const std::vector<std::string>& actions) {
|
||||||
|
std::ostringstream script;
|
||||||
|
script << "# Generated GUI Automation Script\n";
|
||||||
|
script << "test: \"Automated Edit\"\n";
|
||||||
|
script << "steps:\n";
|
||||||
|
for (const auto& action : actions) {
|
||||||
|
script << " - " << action << "\n";
|
||||||
|
}
|
||||||
|
return script.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AdvancedRouter::InferDataType(const std::vector<uint8_t>& data) {
|
||||||
|
if (data.size() == 8) return "tile16 data";
|
||||||
|
if (data.size() % 3 == 0 && data.size() <= 48) return "sprite data";
|
||||||
|
if (data.size() == 32) return "palette data (16 colors)";
|
||||||
|
if (data.size() > 1000) return "compressed data block";
|
||||||
|
return "unknown data";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> AdvancedRouter::ExtractPatterns(
|
||||||
|
const std::vector<uint8_t>& data) {
|
||||||
|
std::vector<std::string> patterns;
|
||||||
|
|
||||||
|
// Check for repeating bytes
|
||||||
|
if (data.size() > 2) {
|
||||||
|
bool all_same = true;
|
||||||
|
for (size_t i = 1; i < data.size(); ++i) {
|
||||||
|
if (data[i] != data[0]) {
|
||||||
|
all_same = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (all_same) {
|
||||||
|
patterns.push_back(absl::StrFormat("Repeating byte: 0x%02X", data[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for ascending/descending sequences
|
||||||
|
if (data.size() > 3) {
|
||||||
|
bool ascending = true, descending = true;
|
||||||
|
for (size_t i = 1; i < data.size(); ++i) {
|
||||||
|
if (data[i] != data[i-1] + 1) ascending = false;
|
||||||
|
if (data[i] != data[i-1] - 1) descending = false;
|
||||||
|
}
|
||||||
|
if (ascending) patterns.push_back("Ascending sequence");
|
||||||
|
if (descending) patterns.push_back("Descending sequence");
|
||||||
|
}
|
||||||
|
|
||||||
|
return patterns;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AdvancedRouter::FormatForAgent(const std::string& raw_data) {
|
||||||
|
// Format data for easy agent consumption
|
||||||
|
return "```\n" + raw_data + "\n```";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace agent
|
||||||
|
} // namespace cli
|
||||||
|
} // namespace yaze
|
||||||
85
src/cli/service/agent/advanced_routing.h
Normal file
85
src/cli/service/agent/advanced_routing.h
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#ifndef YAZE_CLI_SERVICE_AGENT_ADVANCED_ROUTING_H_
|
||||||
|
#define YAZE_CLI_SERVICE_AGENT_ADVANCED_ROUTING_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include "absl/status/statusor.h"
|
||||||
|
|
||||||
|
namespace yaze {
|
||||||
|
class Rom;
|
||||||
|
|
||||||
|
namespace cli {
|
||||||
|
namespace agent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Advanced routing system for agent tool responses
|
||||||
|
*
|
||||||
|
* Optimizes information flow back to agent for:
|
||||||
|
* - Map editing with GUI automation
|
||||||
|
* - Hex data analysis and pattern recognition
|
||||||
|
* - Multi-step operations with context preservation
|
||||||
|
*/
|
||||||
|
class AdvancedRouter {
|
||||||
|
public:
|
||||||
|
struct RouteContext {
|
||||||
|
Rom* rom;
|
||||||
|
std::string user_intent;
|
||||||
|
std::vector<std::string> tool_calls_made;
|
||||||
|
std::string accumulated_knowledge;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RoutedResponse {
|
||||||
|
std::string summary; // High-level answer
|
||||||
|
std::string detailed_data; // Raw data for agent processing
|
||||||
|
std::string next_steps; // Suggested follow-up actions
|
||||||
|
std::vector<std::string> gui_actions; // For test harness
|
||||||
|
bool needs_approval; // For proposals
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Route hex data analysis response
|
||||||
|
*/
|
||||||
|
static RoutedResponse RouteHexAnalysis(
|
||||||
|
const std::vector<uint8_t>& data,
|
||||||
|
uint32_t address,
|
||||||
|
const RouteContext& ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Route map editing response
|
||||||
|
*/
|
||||||
|
static RoutedResponse RouteMapEdit(
|
||||||
|
const std::string& edit_intent,
|
||||||
|
const RouteContext& ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Route palette analysis response
|
||||||
|
*/
|
||||||
|
static RoutedResponse RoutePaletteAnalysis(
|
||||||
|
const std::vector<uint16_t>& colors,
|
||||||
|
const RouteContext& ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Synthesize multi-tool response
|
||||||
|
*/
|
||||||
|
static RoutedResponse SynthesizeMultiToolResponse(
|
||||||
|
const std::vector<std::string>& tool_results,
|
||||||
|
const RouteContext& ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate GUI automation script
|
||||||
|
*/
|
||||||
|
static std::string GenerateGUIScript(
|
||||||
|
const std::vector<std::string>& actions);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::string InferDataType(const std::vector<uint8_t>& data);
|
||||||
|
static std::vector<std::string> ExtractPatterns(const std::vector<uint8_t>& data);
|
||||||
|
static std::string FormatForAgent(const std::string& raw_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace agent
|
||||||
|
} // namespace cli
|
||||||
|
} // namespace yaze
|
||||||
|
|
||||||
|
#endif // YAZE_CLI_SERVICE_AGENT_ADVANCED_ROUTING_H_
|
||||||
206
src/cli/service/agent/agent_pretraining.cc
Normal file
206
src/cli/service/agent/agent_pretraining.cc
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
#include "cli/service/agent/agent_pretraining.h"
|
||||||
|
|
||||||
|
#include "absl/strings/str_format.h"
|
||||||
|
#include "app/rom.h"
|
||||||
|
#include "app/zelda3/overworld/overworld.h"
|
||||||
|
|
||||||
|
namespace yaze {
|
||||||
|
namespace cli {
|
||||||
|
namespace agent {
|
||||||
|
|
||||||
|
std::vector<AgentPretraining::KnowledgeModule> AgentPretraining::GetModules() {
|
||||||
|
return {
|
||||||
|
{"rom_structure", GetRomStructureKnowledge(nullptr), true},
|
||||||
|
{"hex_analysis", GetHexAnalysisKnowledge(), true},
|
||||||
|
{"map_editing", GetMapEditingKnowledge(), true},
|
||||||
|
{"tool_usage", GetToolUsageExamples(), true},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AgentPretraining::GetRomStructureKnowledge(Rom* rom) {
|
||||||
|
return R"(
|
||||||
|
# ALTTP ROM Structure Deep Dive
|
||||||
|
|
||||||
|
## Memory Map
|
||||||
|
- 0x00000-0x07FFF: Header + Low ROM
|
||||||
|
- 0x08000-0x0FFFF: Character data
|
||||||
|
- 0x10000-0x1FFFF: Overworld maps
|
||||||
|
- 0x1C800-0x1D7FF: Overworld tile16 data
|
||||||
|
- 0x20000-0x2FFFF: Dungeon rooms (296 rooms)
|
||||||
|
- 0xDE6C8-0xDEDC7: Overworld palettes
|
||||||
|
- 0xDD308-0xDD3C7: Dungeon palettes
|
||||||
|
|
||||||
|
## Overworld Structure
|
||||||
|
- 64 maps (0x00-0x3F): Light world + Dark world
|
||||||
|
- Each map: 32x32 tiles (1024 tile16s)
|
||||||
|
- Tile16 address = 0x1C800 + (tile_id * 8 bytes)
|
||||||
|
- Map data stored compressed
|
||||||
|
|
||||||
|
## Dungeon Structure
|
||||||
|
- 296 rooms total (0x00-0x127)
|
||||||
|
- Room header: 14 bytes
|
||||||
|
- Sprite data: 3 bytes per sprite, up to 16 sprites
|
||||||
|
- Layer 1/2 separate data
|
||||||
|
- Object encoding: Layer/Size/X/Y format
|
||||||
|
|
||||||
|
## Palette System
|
||||||
|
- 8 groups, 8 palettes per group
|
||||||
|
- 16 colors per palette (SNES 555 format)
|
||||||
|
- $0000-$7FFF range (5 bits per R/G/B channel)
|
||||||
|
- Conversion: RGB8 = (SNES_val & 0x1F) << 3
|
||||||
|
|
||||||
|
## Critical Addresses
|
||||||
|
- Sprite sheets: 0x80000+
|
||||||
|
- Entrance table: 0x02C000
|
||||||
|
- Item table: 0x0DC800
|
||||||
|
- Text data: 0x0E0000+
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AgentPretraining::GetHexAnalysisKnowledge() {
|
||||||
|
return R"(
|
||||||
|
# Hex Data Analysis Patterns
|
||||||
|
|
||||||
|
## Pattern Recognition
|
||||||
|
|
||||||
|
### Sprite Data (3-byte pattern)
|
||||||
|
- Byte 0: Sprite ID (0x00-0xFF)
|
||||||
|
- Byte 1: X position in room
|
||||||
|
- Byte 2: Y position in room
|
||||||
|
- Example: "09 48 56" = Sprite 0x09 at (72, 86)
|
||||||
|
|
||||||
|
### Tile16 Structure (8 bytes)
|
||||||
|
- Bytes 0-1: Top-left tile8
|
||||||
|
- Bytes 2-3: Top-right tile8
|
||||||
|
- Bytes 4-5: Bottom-left tile8
|
||||||
|
- Bytes 6-7: Bottom-right tile8
|
||||||
|
- Format: tile8_id (lower byte) + properties (upper byte)
|
||||||
|
|
||||||
|
### Pointers (Little Endian)
|
||||||
|
- 2-byte pointer: Low byte first, high byte second
|
||||||
|
- Example: "00 1C" = 0x1C00 (address 0x001C00)
|
||||||
|
- SNES addressing: Add bank byte for 24-bit
|
||||||
|
|
||||||
|
## Search Strategies
|
||||||
|
|
||||||
|
### Finding Unused Space
|
||||||
|
- Pattern: "FF FF FF FF" (often unused)
|
||||||
|
- Pattern: "00 00 00 00" (zeroed regions)
|
||||||
|
|
||||||
|
### Finding Sprite Definitions
|
||||||
|
- Search for known sprite IDs
|
||||||
|
- Look for X/Y coordinate patterns (0x00-0x1F typical range)
|
||||||
|
|
||||||
|
### Finding Compressed Data
|
||||||
|
- Look for compression headers (0xE0-0xFF often signify compression)
|
||||||
|
- Data density changes (sparse vs dense byte values)
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AgentPretraining::GetMapEditingKnowledge() {
|
||||||
|
return R"(
|
||||||
|
# Map Editing Workflow with Test Harness
|
||||||
|
|
||||||
|
## Tile Placement Flow
|
||||||
|
1. Parse natural language: "Place water tile at (5, 7)"
|
||||||
|
2. Tool chain:
|
||||||
|
a. overworld-find-tile to get water tile ID
|
||||||
|
b. Calculate screen coordinates from game coords
|
||||||
|
c. Generate GUI action: Click(overworld_canvas, x, y)
|
||||||
|
d. Generate GUI action: SelectTile(tile_id)
|
||||||
|
e. Generate GUI action: Click(target_x, target_y)
|
||||||
|
|
||||||
|
## Coordinate Systems
|
||||||
|
- Game coords: Tile-based (0-31 for 32x32 map)
|
||||||
|
- Screen coords: Pixel-based, depends on zoom/scroll
|
||||||
|
- Conversion: screen_x = game_x * tile_size * zoom + canvas_offset_x
|
||||||
|
|
||||||
|
## GUI Automation Best Practices
|
||||||
|
- Always wait for UI updates (Wait(100ms) between actions)
|
||||||
|
- Assert widget states before clicking
|
||||||
|
- Screenshot before/after for verification
|
||||||
|
- Use widget discovery to find exact IDs
|
||||||
|
|
||||||
|
## Proposal System Integration
|
||||||
|
- Read-only tools: Execute directly
|
||||||
|
- Write operations: Submit as proposal first
|
||||||
|
- Wait for approval before proceeding
|
||||||
|
- Show user what will change (diff view)
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AgentPretraining::GetToolUsageExamples() {
|
||||||
|
return R"(
|
||||||
|
# Tool Usage Examples & Chaining
|
||||||
|
|
||||||
|
## Example 1: Find and Analyze Sprites
|
||||||
|
User: "What enemies are in Hyrule Castle?"
|
||||||
|
Tool chain:
|
||||||
|
1. resource-search --type=dungeon --query=hyrule
|
||||||
|
2. dungeon-list-sprites --dungeon=hyrule_castle
|
||||||
|
3. resource-list --type=sprite (to get sprite names)
|
||||||
|
Result: "Hyrule Castle (dungeon 0) has 3 guards (sprite 0x41), 2 knights..."
|
||||||
|
|
||||||
|
## Example 2: Palette Investigation
|
||||||
|
User: "What colors are used for grass?"
|
||||||
|
Tool chain:
|
||||||
|
1. overworld-find-tile --tile_id=0x20 (grass tile)
|
||||||
|
2. palette-get-colors --group=0 --palette=0
|
||||||
|
3. palette-analyze --type=palette --id=0/0
|
||||||
|
Result: "Grass uses palette 0/0 with colors: light green #98FB98..."
|
||||||
|
|
||||||
|
## Example 3: Hex Pattern Search
|
||||||
|
User: "Find all chests in the ROM"
|
||||||
|
Tool chain:
|
||||||
|
1. hex-search --pattern="20 ?? ??" (chest object code 0x20)
|
||||||
|
2. For each match, hex-read context bytes
|
||||||
|
3. Parse room numbers from addresses
|
||||||
|
Result: "Found 50 chests across 30 rooms..."
|
||||||
|
|
||||||
|
## Example 4: Complex Edit Planning
|
||||||
|
User: "Add a new enemy to room 5"
|
||||||
|
Steps:
|
||||||
|
1. dungeon-describe-room --room_id=5 (check current sprites)
|
||||||
|
2. resource-list --type=sprite (available enemies)
|
||||||
|
3. todo-create --title="Add sprite to room 5" --steps="find_sprite,get_coords,write_data"
|
||||||
|
4. hex-read --address=<room_5_sprite_addr> (check free slots)
|
||||||
|
5. Submit proposal with hex-write
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AgentPretraining::GeneratePretrainingPrompt(Rom* rom) {
|
||||||
|
std::string prompt = "# Agent Pre-Training Session\n\n";
|
||||||
|
prompt += "You are being initialized with deep knowledge about this ROM.\n\n";
|
||||||
|
|
||||||
|
if (rom && rom->is_loaded()) {
|
||||||
|
prompt += absl::StrFormat("## Current ROM: %s\n", rom->title());
|
||||||
|
prompt += absl::StrFormat("Size: %zu bytes\n", rom->size());
|
||||||
|
prompt += absl::StrFormat("Type: %s\n\n", rom->is_expanded() ? "Expanded" : "Vanilla");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& module : GetModules()) {
|
||||||
|
prompt += absl::StrFormat("## Module: %s\n", module.name);
|
||||||
|
prompt += module.content;
|
||||||
|
prompt += "\n---\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt += R"(
|
||||||
|
## Your Capabilities After Training
|
||||||
|
|
||||||
|
You now understand:
|
||||||
|
✓ ROM memory layout and addressing
|
||||||
|
✓ How to chain tools for complex analysis
|
||||||
|
✓ Hex pattern recognition and data structures
|
||||||
|
✓ GUI automation for map editing
|
||||||
|
✓ Proposal system for safe ROM modification
|
||||||
|
|
||||||
|
**Test your knowledge**: When I ask about sprites, dungeons, or tiles,
|
||||||
|
use multiple tools in one response to give comprehensive answers.
|
||||||
|
)";
|
||||||
|
|
||||||
|
return prompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace agent
|
||||||
|
} // namespace cli
|
||||||
|
} // namespace yaze
|
||||||
63
src/cli/service/agent/agent_pretraining.h
Normal file
63
src/cli/service/agent/agent_pretraining.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#ifndef YAZE_CLI_SERVICE_AGENT_AGENT_PRETRAINING_H_
|
||||||
|
#define YAZE_CLI_SERVICE_AGENT_AGENT_PRETRAINING_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "absl/status/status.h"
|
||||||
|
|
||||||
|
namespace yaze {
|
||||||
|
class Rom;
|
||||||
|
|
||||||
|
namespace cli {
|
||||||
|
namespace agent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pre-training system for AI agents
|
||||||
|
*
|
||||||
|
* Provides structured knowledge injection before interactive use.
|
||||||
|
* Teaches agent about ROM structure, common patterns, and tool usage.
|
||||||
|
*/
|
||||||
|
class AgentPretraining {
|
||||||
|
public:
|
||||||
|
struct KnowledgeModule {
|
||||||
|
std::string name;
|
||||||
|
std::string content;
|
||||||
|
bool required;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load all pre-training modules
|
||||||
|
*/
|
||||||
|
static std::vector<KnowledgeModule> GetModules();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get ROM structure explanation
|
||||||
|
*/
|
||||||
|
static std::string GetRomStructureKnowledge(Rom* rom);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get hex data analysis patterns
|
||||||
|
*/
|
||||||
|
static std::string GetHexAnalysisKnowledge();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get map editing workflow
|
||||||
|
*/
|
||||||
|
static std::string GetMapEditingKnowledge();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get tool usage examples
|
||||||
|
*/
|
||||||
|
static std::string GetToolUsageExamples();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate pre-training prompt for agent
|
||||||
|
*/
|
||||||
|
static std::string GeneratePretrainingPrompt(Rom* rom);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace agent
|
||||||
|
} // namespace cli
|
||||||
|
} // namespace yaze
|
||||||
|
|
||||||
|
#endif // YAZE_CLI_SERVICE_AGENT_AGENT_PRETRAINING_H_
|
||||||
Reference in New Issue
Block a user