9#ifndef YAZE_SRC_CLI_SERVICE_AGENT_TOOL_SCHEMAS_H_
10#define YAZE_SRC_CLI_SERVICE_AGENT_TOOL_SCHEMAS_H_
15#include "absl/strings/str_cat.h"
16#include "absl/strings/str_join.h"
34 std::string
json =
"{";
35 json +=
"\"name\": \"" +
name +
"\", ";
36 json +=
"\"type\": \"" +
type +
"\", ";
38 json +=
"\"required\": " + std::string(
required ?
"true" :
"false");
43 json +=
", \"enum\": [";
73 std::string
json =
"{\n";
74 json +=
" \"name\": \"" +
name +
"\",\n";
79 json +=
" \"parameters\": {\n";
80 json +=
" \"type\": \"object\",\n";
81 json +=
" \"properties\": {\n";
83 for (
size_t i = 0; i <
arguments.size(); ++i) {
85 json +=
" \"" + arg.name +
"\": {\n";
86 json +=
" \"type\": \"" + arg.type +
"\",\n";
87 json +=
" \"description\": \"" + arg.description +
"\"";
88 if (!arg.enum_values.empty()) {
89 json +=
",\n \"enum\": [";
90 for (
size_t j = 0; j < arg.enum_values.size(); ++j) {
91 json +=
"\"" + arg.enum_values[j] +
"\"";
92 if (j < arg.enum_values.size() - 1)
json +=
", ";
104 json +=
" \"required\": [";
108 if (!first)
json +=
", ";
109 json +=
"\"" + arg.name +
"\"";
117 json +=
" \"requires_rom\": " + std::string(
requires_rom ?
"true" :
"false")
119 json +=
" \"requires_grpc\": " +
123 json +=
",\n \"examples\": [\n";
124 for (
size_t i = 0; i <
examples.size(); ++i) {
133 json +=
",\n \"related_tools\": [";
150 md +=
"### " +
name +
"\n\n";
157 md +=
"**Category:** " +
category +
"\n\n";
160 md +=
"**Arguments:**\n\n";
161 md +=
"| Name | Type | Required | Description |\n";
162 md +=
"|------|------|----------|-------------|\n";
164 md +=
"| `" + arg.name +
"` | " + arg.type +
" | ";
165 md += (arg.required ?
"Yes" :
"No") +
" | ";
166 md += arg.description +
" |\n";
172 md +=
"**Examples:**\n\n```bash\n";
180 md +=
"**Related:** " + absl::StrJoin(
related_tools,
", ") +
"\n\n";
201 return it !=
schemas_.end() ? &it->second :
nullptr;
205 std::vector<ToolSchema> result;
206 for (
const auto& [_, schema] :
schemas_) {
207 result.push_back(schema);
213 std::vector<ToolSchema> result;
214 for (
const auto& [_, schema] :
schemas_) {
216 result.push_back(schema);
226 std::string
json =
"[\n";
228 for (
const auto& [_, schema] :
schemas_) {
229 if (!first)
json +=
",\n";
230 json += schema.ToJson();
241 std::string md =
"# Z3ED Tool Reference\n\n";
244 std::map<std::string, std::vector<const ToolSchema*>> by_category;
245 for (
const auto& [_, schema] :
schemas_) {
246 by_category[schema.category].push_back(&schema);
249 for (
const auto& [
category, tools] : by_category) {
251 for (
const auto* tool : tools) {
252 md += tool->ToMarkdown();
263 std::string prompt =
"## Available Tools\n\n";
265 "You can call the following tools to interact with the ROM and "
268 for (
const auto& [_, schema] :
schemas_) {
269 prompt +=
"- **" + schema.name +
"**: " + schema.description +
"\n";
270 if (!schema.arguments.empty()) {
271 prompt +=
" Arguments: ";
272 for (
size_t i = 0; i < schema.arguments.size(); ++i) {
273 const auto& arg = schema.arguments[i];
275 if (arg.required) prompt +=
"*";
276 if (i < schema.arguments.size() - 1) prompt +=
", ";
292 .description =
"List all available tools",
293 .detailed_help =
"Returns a JSON array of all tools the AI can "
294 "call, including their names, categories, and "
295 "brief descriptions.",
297 .examples = {
"z3ed tools-list"},
298 .requires_rom =
false});
302 .description =
"Get detailed information about a specific tool",
303 .arguments = {{.name =
"name",
305 .description =
"Name of the tool to describe",
307 .examples = {
"z3ed tools-describe --name=dungeon-describe-room"},
308 .requires_rom =
false});
312 .description =
"Search tools by keyword",
313 .arguments = {{.name =
"query",
315 .description =
"Search query",
317 .examples = {
"z3ed tools-search --query=sprite"},
318 .requires_rom =
false});
322 .category =
"resource",
323 .description =
"List resource labels for a specific type",
324 .arguments = {{.name =
"type",
326 .description =
"Resource type to list",
328 .enum_values = {
"dungeon",
"overworld",
"sprite",
329 "palette",
"message"}}},
330 .examples = {
"z3ed resource-list --type=dungeon"},
331 .related_tools = {
"resource-search"}});
335 {.name =
"dungeon-describe-room",
336 .category =
"dungeon",
337 .description =
"Get detailed description of a dungeon room",
339 "Returns information about room layout, objects, sprites, "
340 "and properties for the specified room ID.",
341 .arguments = {{.name =
"room",
343 .description =
"Room ID (0-295)",
345 .examples = {
"z3ed dungeon-describe-room --room=5"},
346 .related_tools = {
"dungeon-list-sprites",
"dungeon-list-objects"}});
349 Register({.name =
"overworld-describe-map",
350 .category =
"overworld",
351 .description =
"Get detailed description of an overworld map",
352 .arguments = {{.name =
"map",
354 .description =
"Map ID (0-159)",
356 .examples = {
"z3ed overworld-describe-map --map=0"},
357 .related_tools = {
"overworld-list-sprites",
"overworld-find-tile"}});
360 Register({.name =
"filesystem-list",
361 .category =
"filesystem",
362 .description =
"List directory contents",
363 .arguments = {{.name =
"path",
365 .description =
"Directory path to list",
367 .examples = {
"z3ed filesystem-list --path=src/app"},
368 .requires_rom =
false,
369 .related_tools = {
"filesystem-read",
"filesystem-exists"}});
371 Register({.name =
"filesystem-read",
372 .category =
"filesystem",
373 .description =
"Read file contents",
374 .arguments = {{.name =
"path",
376 .description =
"File path to read",
380 .description =
"Maximum lines to read",
382 .default_value =
"100"}},
383 .examples = {
"z3ed filesystem-read --path=src/app/rom.h"},
384 .requires_rom =
false});
388 .category =
"memory",
389 .description =
"List known ALTTP memory regions",
390 .detailed_help =
"Returns a list of known memory regions in A "
391 "Link to the Past, including player state, "
392 "sprites, save data, and system variables.",
394 .examples = {
"z3ed memory-regions"},
395 .requires_rom =
false,
396 .related_tools = {
"memory-analyze",
"memory-search"}});
399 Register({.name =
"tools-harness-state",
401 .description =
"Generate WRAM state for test harnesses",
403 "Runs the emulator to the main game loop and dumps the "
404 "complete WRAM state and register values to a C++ header "
405 "file for use in test harnesses.",
406 .arguments = {{.name =
"rom",
408 .description =
"Path to ROM file",
412 .description =
"Output header file path",
414 .examples = {
"z3ed tools-harness-state --rom=zelda3.sfc "
415 "--output=harness_state.h"},
416 .requires_rom =
false});
418 Register({.name =
"tools-extract-golden",
420 .description =
"Extract comprehensive golden data from ROM",
421 .arguments = {{.name =
"rom",
423 .description =
"Path to ROM file",
427 .description =
"Output header file path",
429 .examples = {
"z3ed tools-extract-golden --rom=zelda3.sfc "
430 "--output=golden_data.h"}});
433 Register({.name =
"visual-find-similar-tiles",
434 .category =
"visual",
435 .description =
"Find tiles with similar patterns to a reference",
437 "Compares a reference tile against all tiles in graphics "
438 "sheets and returns matches above the similarity threshold. "
439 "Useful for finding duplicate or near-duplicate tiles for "
441 .arguments = {{.name =
"tile_id",
443 .description =
"Reference tile ID to compare",
447 .description =
"Graphics sheet index (0-222)",
449 .default_value =
"0"},
450 {.name =
"threshold",
452 .description =
"Minimum similarity score (0-100)",
454 .default_value =
"80"},
457 .description =
"Comparison method",
459 .default_value =
"structural",
460 .enum_values = {
"pixel",
"structural"}}},
461 .examples = {
"z3ed visual-find-similar-tiles --tile_id=42",
462 "z3ed visual-find-similar-tiles --tile_id=10 "
463 "--sheet=5 --threshold=90"},
464 .related_tools = {
"visual-analyze-spritesheet",
465 "visual-tile-histogram"}});
467 Register({.name =
"visual-analyze-spritesheet",
468 .category =
"visual",
469 .description =
"Identify unused regions in graphics sheets",
471 "Scans graphics sheets for contiguous empty regions that "
472 "can be used for custom graphics in ROM hacking. Reports "
473 "the location and size of each free region.",
474 .arguments = {{.name =
"sheet",
476 .description =
"Specific sheet to analyze (all if omitted)",
478 {.name =
"tile_size",
480 .description =
"Tile size to check (8 or 16)",
482 .default_value =
"8",
483 .enum_values = {
"8",
"16"}}},
484 .examples = {
"z3ed visual-analyze-spritesheet",
485 "z3ed visual-analyze-spritesheet --sheet=10 "
487 .related_tools = {
"visual-find-similar-tiles"}});
489 Register({.name =
"visual-palette-usage",
490 .category =
"visual",
491 .description =
"Analyze palette usage statistics across maps",
493 "Analyzes which palette indices are used across overworld "
494 "maps and dungeon rooms. Helps identify under-utilized "
495 "palettes and optimization opportunities.",
496 .arguments = {{.name =
"type",
498 .description =
"Map type to analyze",
500 .default_value =
"all",
501 .enum_values = {
"overworld",
"dungeon",
"all"}}},
502 .examples = {
"z3ed visual-palette-usage",
503 "z3ed visual-palette-usage --type=dungeon"},
504 .related_tools = {
"visual-tile-histogram"}});
506 Register({.name =
"visual-tile-histogram",
507 .category =
"visual",
508 .description =
"Generate frequency histogram of tile usage",
510 "Counts the frequency of each tile ID used across tilemaps "
511 "to identify commonly and rarely used tiles. Useful for "
512 "understanding tile distribution and finding candidates "
514 .arguments = {{.name =
"type",
516 .description =
"Map type to analyze",
518 .default_value =
"overworld",
519 .enum_values = {
"overworld",
"dungeon"}},
522 .description =
"Number of top entries to return",
524 .default_value =
"20"}},
525 .examples = {
"z3ed visual-tile-histogram",
526 "z3ed visual-tile-histogram --type=dungeon --top=50"},
527 .related_tools = {
"visual-palette-usage",
528 "visual-find-similar-tiles"}});
534 Register({.name =
"codegen-asm-hook",
535 .category =
"codegen",
536 .description =
"Generate ASM hook at ROM address",
538 "Generates Asar-compatible ASM code to hook into the ROM at "
539 "a specified address using JSL. Validates the address is safe "
540 "and not already hooked. Includes known safe hook locations.",
541 .arguments = {{.name =
"address",
543 .description =
"ROM address to hook (hex)",
547 .description =
"Label name for the hook",
551 .description =
"Number of NOP bytes to add",
553 .default_value =
"1"}},
554 .examples = {
"z3ed codegen-asm-hook --address=0x02AB08 --label=MyHook",
555 "z3ed codegen-asm-hook --address=0x00893D --label=ForceBlankHook --nop-fill=2"},
556 .requires_rom =
true,
557 .related_tools = {
"codegen-freespace-patch",
"memory-analyze"}});
559 Register({.name =
"codegen-freespace-patch",
560 .category =
"codegen",
561 .description =
"Generate patch using detected free regions",
563 "Detects available freespace in the ROM (regions with >80% "
564 "0x00/0xFF bytes) and generates a patch to allocate space "
565 "for custom code. Returns available regions and generated ASM.",
566 .arguments = {{.name =
"label",
568 .description =
"Label for the code block",
572 .description =
"Size in bytes needed (hex)",
574 {.name =
"prefer-bank",
576 .description =
"Preferred bank number (hex)",
578 .examples = {
"z3ed codegen-freespace-patch --label=MyCode --size=0x100",
579 "z3ed codegen-freespace-patch --label=CustomRoutine --size=0x200 --prefer-bank=0x3F"},
580 .requires_rom =
true,
581 .related_tools = {
"codegen-asm-hook",
"memory-regions"}});
583 Register({.name =
"codegen-sprite-template",
584 .category =
"codegen",
585 .description =
"Generate sprite ASM from template",
587 "Generates a complete sprite ASM template with init and main "
588 "state machine. Includes SNES sprite variable documentation "
589 "and proper PHB/PLB register preservation.",
590 .arguments = {{.name =
"name",
592 .description =
"Sprite name/label",
594 {.name =
"init-code",
596 .description =
"Initialization ASM code",
598 {.name =
"main-code",
600 .description =
"Main loop ASM code",
602 .examples = {
"z3ed codegen-sprite-template --name=MySprite",
603 "z3ed codegen-sprite-template --name=CustomChest --init-code=\"LDA #$42 : STA $0DC0,X\""},
604 .requires_rom =
false,
605 .related_tools = {
"codegen-event-handler"}});
607 Register({.name =
"codegen-event-handler",
608 .category =
"codegen",
609 .description =
"Generate event handler code",
611 "Generates ASM event handler code for NMI, IRQ, or Reset "
612 "handlers. Includes proper state preservation and known "
613 "hook addresses for each event type.",
614 .arguments = {{.name =
"type",
616 .description =
"Event type",
618 .enum_values = {
"nmi",
"irq",
"reset"}},
621 .description =
"Handler label name",
623 {.name =
"custom-code",
625 .description =
"Custom ASM code",
627 .examples = {
"z3ed codegen-event-handler --type=nmi --label=MyVBlank",
628 "z3ed codegen-event-handler --type=nmi --label=MyHandler --custom-code=\"LDA #$80 : STA $2100\""},
629 .requires_rom =
false,
630 .related_tools = {
"codegen-asm-hook",
"codegen-sprite-template"}});
637 .category =
"project",
638 .description =
"Show current project state and pending edits",
640 "Displays current project state including loaded ROM info, "
641 "pending uncommitted edits, available snapshots, and ROM "
642 "checksum for validation.",
644 .examples = {
"z3ed project-status"},
645 .requires_rom =
true,
646 .related_tools = {
"project-snapshot",
"project-restore"}});
648 Register({.name =
"project-snapshot",
649 .category =
"project",
650 .description =
"Create named checkpoint with edit deltas",
652 "Creates a named snapshot storing all pending edits as "
653 "deltas (not full ROM copy). Includes ROM checksum for "
654 "validation when restoring.",
655 .arguments = {{.name =
"name",
657 .description =
"Snapshot name",
659 {.name =
"description",
661 .description =
"Optional description",
663 .examples = {
"z3ed project-snapshot --name=before-edit",
664 "z3ed project-snapshot --name=dungeon-complete --description=\"Finished dungeon 1\""},
665 .requires_rom =
true,
666 .related_tools = {
"project-status",
"project-restore",
"project-diff"}});
668 Register({.name =
"project-restore",
669 .category =
"project",
670 .description =
"Restore ROM to named checkpoint",
672 "Restores the ROM to a previously saved snapshot state by "
673 "replaying the stored edit deltas. Validates ROM checksum "
674 "to ensure correct base ROM.",
675 .arguments = {{.name =
"name",
677 .description =
"Snapshot name to restore",
679 .examples = {
"z3ed project-restore --name=before-edit"},
680 .requires_rom =
true,
681 .related_tools = {
"project-snapshot",
"project-status"}});
684 .category =
"project",
685 .description =
"Export project as portable archive",
687 "Exports the project metadata and all snapshots as a "
688 "portable archive file. Optionally includes the base ROM.",
689 .arguments = {{.name =
"path",
691 .description =
"Output file path",
693 {.name =
"include-rom",
695 .description =
"Include base ROM in export",
697 .examples = {
"z3ed project-export --path=myproject.tar.gz",
698 "z3ed project-export --path=backup.tar.gz --include-rom"},
699 .requires_rom =
true,
700 .related_tools = {
"project-import"}});
703 .category =
"project",
704 .description =
"Import project archive",
706 "Imports a project archive and loads its metadata and "
707 "snapshots. Validates project structure and checksums.",
708 .arguments = {{.name =
"path",
710 .description =
"Archive file path",
712 .examples = {
"z3ed project-import --path=myproject.tar.gz"},
713 .requires_rom =
false,
714 .related_tools = {
"project-export"}});
717 .category =
"project",
718 .description =
"Compare two project states",
720 "Compares two snapshots and shows the differences in edits "
721 "between them. Useful for reviewing changes between versions.",
722 .arguments = {{.name =
"snapshot1",
724 .description =
"First snapshot name",
726 {.name =
"snapshot2",
728 .description =
"Second snapshot name",
730 .examples = {
"z3ed project-diff --snapshot1=v1 --snapshot2=v2"},
731 .requires_rom =
true,
732 .related_tools = {
"project-snapshot",
"rom-diff"}});
Argument schema for a tool parameter.
std::vector< std::string > enum_values
std::string ToJson() const
std::string default_value