forked from ggml-org/llama.cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
frameforge: load verb definitions from JSON with Delphi Bridge compatibility #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
TheOriginalBytePlayer
merged 6 commits into
master
from
copilot/update-voice-command-integration
Dec 31, 2025
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
36f27c6
Initial plan
Copilot 6c201f4
Add JSON-based verb definitions with basic loading
Copilot cb9a7db
Update JSON format for Delphi Bridge compatibility and add master verbs
Copilot a0b0cab
Add comprehensive tests and documentation for new features
Copilot 791abaf
Add implementation complete summary with examples
Copilot c4b7706
Fix code review issues
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| #include "../tools/frameforge/frameforge-schema.h" | ||
| #include <cassert> | ||
| #include <iostream> | ||
| #include <string> | ||
|
|
||
| using namespace frameforge; | ||
|
|
||
| static void test_load_from_json() { | ||
| std::cout << "Testing JSON loading..." << std::endl; | ||
|
|
||
| std::string json_path = "../tools/frameforge/verb-definitions.json"; | ||
| bool loaded = load_verb_definitions(json_path); | ||
|
|
||
| assert(loaded && "Failed to load verb definitions"); | ||
| assert(are_verb_definitions_loaded() && "Definitions not marked as loaded"); | ||
|
|
||
| std::cout << " ✓ JSON loaded successfully" << std::endl; | ||
| } | ||
|
|
||
| static void test_verb_conversion_with_json() { | ||
| std::cout << "Testing verb conversion with JSON..." << std::endl; | ||
|
|
||
| // Test basic verb | ||
| assert(string_to_verb("PAN") == Verb::PAN); | ||
| assert(verb_to_string(Verb::PAN) == "PAN"); | ||
|
|
||
| // Test alias (PIN -> PAN) | ||
| assert(string_to_verb("PIN") == Verb::PAN); | ||
|
|
||
| // Test case insensitivity | ||
| assert(string_to_verb("pan") == Verb::PAN); | ||
|
|
||
| // Test DELETE alias (REMOVE -> DELETE) | ||
| assert(string_to_verb("REMOVE") == Verb::DELETE); | ||
|
|
||
| std::cout << " ✓ Verb conversion with JSON tests passed" << std::endl; | ||
| } | ||
|
|
||
| static void test_action_group_with_json() { | ||
| std::cout << "Testing action group mapping with JSON..." << std::endl; | ||
|
|
||
| assert(get_action_group_for_verb(Verb::PAN) == ActionGroup::CAMERA_CONTROL); | ||
| assert(get_action_group_for_verb(Verb::SET_POSE) == ActionGroup::ACTOR_POSE); | ||
| assert(get_action_group_for_verb(Verb::ADD) == ActionGroup::OBJECT_MGMT); | ||
| assert(get_action_group_for_verb(Verb::SHOT) == ActionGroup::SHOT_MGMT); | ||
|
|
||
| std::cout << " ✓ Action group with JSON tests passed" << std::endl; | ||
| } | ||
|
|
||
| static void test_required_parameters_with_json() { | ||
| std::cout << "Testing required parameters with JSON..." << std::endl; | ||
|
|
||
| auto pan_params = get_required_parameters(Verb::PAN); | ||
| assert(pan_params.size() == 1); | ||
| assert(pan_params[0] == "direction"); | ||
|
|
||
| auto dolly_params = get_required_parameters(Verb::DOLLY); | ||
| assert(dolly_params.size() == 1); | ||
| assert(dolly_params[0] == "direction"); | ||
|
|
||
| auto lean_params = get_required_parameters(Verb::LEAN); | ||
| assert(lean_params.size() == 2); | ||
| assert(lean_params[0] == "direction"); | ||
| assert(lean_params[1] == "degrees"); | ||
|
|
||
| auto add_params = get_required_parameters(Verb::ADD); | ||
| assert(add_params.size() == 1); | ||
| assert(add_params[0] == "target"); | ||
|
|
||
| std::cout << " ✓ Required parameters with JSON tests passed" << std::endl; | ||
| } | ||
|
|
||
| static void test_fallback_without_json() { | ||
| std::cout << "Testing fallback without JSON (hard-coded defaults)..." << std::endl; | ||
|
|
||
| // Test that the system still works without loading JSON | ||
| assert(string_to_verb("TILT") == Verb::TILT); | ||
| assert(get_action_group_for_verb(Verb::TILT) == ActionGroup::CAMERA_CONTROL); | ||
|
|
||
| auto tilt_params = get_required_parameters(Verb::TILT); | ||
| assert(tilt_params.size() == 1); | ||
| assert(tilt_params[0] == "direction"); | ||
|
|
||
| std::cout << " ✓ Fallback tests passed" << std::endl; | ||
| } | ||
|
|
||
| int main() { | ||
| std::cout << "Running FrameForge JSON Loader Tests..." << std::endl; | ||
| std::cout << "========================================" << std::endl; | ||
|
|
||
| try { | ||
| // First test fallback without JSON | ||
| test_fallback_without_json(); | ||
|
|
||
| // Then test with JSON loaded | ||
| test_load_from_json(); | ||
| test_verb_conversion_with_json(); | ||
| test_action_group_with_json(); | ||
| test_required_parameters_with_json(); | ||
|
|
||
| std::cout << "========================================" << std::endl; | ||
| std::cout << "All tests passed! ✓" << std::endl; | ||
| return 0; | ||
| } catch (const std::exception & e) { | ||
| std::cerr << "Test failed with exception: " << e.what() << std::endl; | ||
| return 1; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,240 @@ | ||
| #include "../tools/frameforge/frameforge-schema.h" | ||
| #include "../tools/frameforge/frameforge-validator.h" | ||
| #include "../tools/frameforge/frameforge-json.h" | ||
|
|
||
| #include <cassert> | ||
| #include <iostream> | ||
| #include <string> | ||
|
|
||
| using namespace frameforge; | ||
|
|
||
| static void test_master_verb_detection() { | ||
| std::cout << "Testing master verb detection..." << std::endl; | ||
|
|
||
| assert(is_master_verb(Verb::START)); | ||
| assert(is_master_verb(Verb::BEGIN)); | ||
| assert(is_master_verb(Verb::HAVE)); | ||
| assert(is_master_verb(Verb::MAKE)); | ||
| assert(is_master_verb(Verb::STOP)); | ||
|
|
||
| assert(!is_master_verb(Verb::PAN)); | ||
| assert(!is_master_verb(Verb::MOVE)); | ||
|
|
||
| std::cout << " ✓ Master verb detection passed" << std::endl; | ||
| } | ||
|
|
||
| static void test_timestamp_generation() { | ||
| std::cout << "Testing timestamp generation..." << std::endl; | ||
|
|
||
| std::string ts = get_current_timestamp(); | ||
| assert(!ts.empty()); | ||
| assert(ts.find('T') != std::string::npos); // Should contain ISO 8601 separator | ||
| assert(ts.find('Z') != std::string::npos); // Should end with Z | ||
|
|
||
| std::cout << " Generated timestamp: " << ts << std::endl; | ||
| std::cout << " ✓ Timestamp generation passed" << std::endl; | ||
| } | ||
|
|
||
| static void test_subject_in_parameters() { | ||
| std::cout << "Testing subject in parameters..." << std::endl; | ||
|
|
||
| Command cmd; | ||
| cmd.verb = Verb::PAN; | ||
| cmd.action_group = ActionGroup::CAMERA_CONTROL; | ||
| cmd.timestamp = get_current_timestamp(); | ||
| cmd.parameters.subject = "Camera1"; | ||
| cmd.parameters.direction = Direction::LEFT; | ||
| cmd.valid = true; | ||
|
|
||
| // Serialize to JSON | ||
| std::string json = command_to_json(cmd); | ||
|
|
||
| // Check that subject is in parameters, not at root | ||
| assert(json.find("\"parameters\"") != std::string::npos); | ||
| assert(json.find("\"subject\": \"Camera1\"") != std::string::npos || | ||
| json.find("\"subject\":\"Camera1\"") != std::string::npos); | ||
|
|
||
| // Parse back | ||
| Command parsed = json_to_command(json); | ||
| assert(parsed.parameters.subject.has_value()); | ||
| assert(parsed.parameters.subject.value() == "Camera1"); | ||
|
|
||
| std::cout << " ✓ Subject in parameters passed" << std::endl; | ||
| } | ||
|
|
||
| static void test_timestamp_in_json() { | ||
| std::cout << "Testing timestamp in JSON..." << std::endl; | ||
|
|
||
| Command cmd; | ||
| cmd.verb = Verb::TILT; | ||
| cmd.action_group = ActionGroup::CAMERA_CONTROL; | ||
| cmd.timestamp = "2024-01-01T12:00:00.000Z"; | ||
| cmd.parameters.direction = Direction::UP; | ||
| cmd.valid = true; | ||
|
|
||
| std::string json = command_to_json(cmd); | ||
|
|
||
| assert(json.find("timestamp") != std::string::npos); | ||
| assert(json.find("2024-01-01T12:00:00.000Z") != std::string::npos); | ||
|
|
||
| std::cout << " ✓ Timestamp in JSON passed" << std::endl; | ||
| } | ||
|
|
||
| static void test_master_verb_command() { | ||
| std::cout << "Testing master verb command..." << std::endl; | ||
|
|
||
| // Create a command like "START PANNING LEFT" | ||
| Command cmd; | ||
| cmd.verb = Verb::PAN; | ||
| cmd.master_verb = Verb::START; | ||
| cmd.action_group = ActionGroup::CAMERA_CONTROL; | ||
| cmd.timestamp = get_current_timestamp(); | ||
| cmd.parameters.direction = Direction::LEFT; | ||
| cmd.parameters.speed = 5.0f; | ||
| cmd.valid = true; | ||
|
|
||
| std::string json = command_to_json(cmd); | ||
|
|
||
| // Should have both verb and master_verb | ||
| assert(json.find("\"verb\": \"PAN\"") != std::string::npos || | ||
| json.find("\"verb\":\"PAN\"") != std::string::npos); | ||
| assert(json.find("\"master_verb\": \"START\"") != std::string::npos || | ||
| json.find("\"master_verb\":\"START\"") != std::string::npos); | ||
|
|
||
| // Parse back | ||
| Command parsed = json_to_command(json); | ||
| assert(parsed.verb == Verb::PAN); | ||
| assert(parsed.master_verb.has_value()); | ||
| assert(parsed.master_verb.value() == Verb::START); | ||
|
|
||
| std::cout << " ✓ Master verb command passed" << std::endl; | ||
| } | ||
|
|
||
| static void test_verb_aliases() { | ||
| std::cout << "Testing verb aliases..." << std::endl; | ||
|
|
||
| // Load definitions to get aliases | ||
| std::string json_path = "../tools/frameforge/verb-definitions.json"; | ||
| bool loaded = load_verb_definitions(json_path); | ||
| assert(loaded); | ||
|
|
||
| // Test aliases | ||
| assert(string_to_verb("PIN") == Verb::PAN); | ||
| assert(string_to_verb("ROOM") == Verb::ZOOM); | ||
| assert(string_to_verb("PUSH") == Verb::DOLLY); | ||
| assert(string_to_verb("REMOVE") == Verb::DELETE); | ||
| assert(string_to_verb("WALK") == Verb::MOVE); | ||
| assert(string_to_verb("RUN") == Verb::MOVE); | ||
| assert(string_to_verb("TURN") == Verb::ROTATE); | ||
|
|
||
| std::cout << " ✓ Verb aliases passed" << std::endl; | ||
| } | ||
|
|
||
| static void test_optional_parameters() { | ||
| std::cout << "Testing optional parameters..." << std::endl; | ||
|
|
||
| // Ensure definitions are loaded | ||
| if (!are_verb_definitions_loaded()) { | ||
| load_verb_definitions("../tools/frameforge/verb-definitions.json"); | ||
| } | ||
|
|
||
| auto pan_optional = get_optional_parameters(Verb::PAN); | ||
| assert(!pan_optional.empty()); | ||
|
|
||
| auto start_optional = get_optional_parameters(Verb::START); | ||
| assert(!start_optional.empty()); | ||
|
|
||
| std::cout << " PAN optional params: " << pan_optional.size() << std::endl; | ||
| std::cout << " START optional params: " << start_optional.size() << std::endl; | ||
| std::cout << " ✓ Optional parameters passed" << std::endl; | ||
| } | ||
|
|
||
| static void test_have_command() { | ||
| std::cout << "Testing HAVE command (HAVE TOM WALK FORWARD)..." << std::endl; | ||
|
|
||
| CommandValidator validator; | ||
|
|
||
| std::string json_str = R"({ | ||
| "verb": "MOVE", | ||
| "master_verb": "HAVE", | ||
| "action_group": "OBJECT_MGMT", | ||
| "timestamp": "2024-01-01T12:00:00.000Z", | ||
| "parameters": { | ||
| "subject": "Tom", | ||
| "target": "Tom", | ||
| "direction": "FORWARD", | ||
| "speed": 5.0 | ||
| } | ||
| })"; | ||
|
|
||
| Command cmd; | ||
| ValidationResult result = validator.validate_json(json_str, cmd); | ||
|
|
||
| assert(result.valid); | ||
| assert(cmd.verb == Verb::MOVE); | ||
| assert(cmd.master_verb.has_value()); | ||
| assert(cmd.master_verb.value() == Verb::HAVE); | ||
| assert(cmd.parameters.subject.has_value()); | ||
| assert(cmd.parameters.subject.value() == "Tom"); | ||
|
|
||
| std::cout << " ✓ HAVE command passed" << std::endl; | ||
| } | ||
|
|
||
| static void test_new_json_format() { | ||
| std::cout << "Testing new Delphi Bridge JSON format..." << std::endl; | ||
|
|
||
| CommandValidator validator; | ||
|
|
||
| // Test complete JSON with all new features | ||
| std::string json_str = R"({ | ||
| "verb": "ZOOM", | ||
| "action_group": "CAMERA_CONTROL", | ||
| "timestamp": "2024-12-30T10:00:00.000Z", | ||
| "parameters": { | ||
| "subject": "MainCamera", | ||
| "direction": "IN", | ||
| "speed": 10.0 | ||
| } | ||
| })"; | ||
|
|
||
| Command cmd; | ||
| ValidationResult result = validator.validate_json(json_str, cmd); | ||
|
|
||
| assert(result.valid); | ||
| assert(cmd.verb == Verb::ZOOM); | ||
| assert(!cmd.timestamp.empty()); | ||
| assert(cmd.parameters.subject.has_value()); | ||
| assert(cmd.parameters.direction.has_value()); | ||
|
|
||
| // Serialize back and ensure all fields present | ||
| std::string output_json = command_to_json(cmd); | ||
| assert(output_json.find("timestamp") != std::string::npos); | ||
| assert(output_json.find("parameters") != std::string::npos); | ||
| assert(output_json.find("subject") != std::string::npos); | ||
|
|
||
| std::cout << " ✓ New JSON format passed" << std::endl; | ||
| } | ||
|
|
||
| int main() { | ||
| std::cout << "Running FrameForge New Features Tests..." << std::endl; | ||
| std::cout << "==========================================" << std::endl; | ||
|
|
||
| try { | ||
| test_master_verb_detection(); | ||
| test_timestamp_generation(); | ||
| test_subject_in_parameters(); | ||
| test_timestamp_in_json(); | ||
| test_master_verb_command(); | ||
| test_verb_aliases(); | ||
| test_optional_parameters(); | ||
| test_have_command(); | ||
| test_new_json_format(); | ||
|
|
||
| std::cout << "==========================================" << std::endl; | ||
| std::cout << "All new feature tests passed! ✓" << std::endl; | ||
| return 0; | ||
| } catch (const std::exception & e) { | ||
| std::cerr << "Test failed with exception: " << e.what() << std::endl; | ||
| return 1; | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test uses "direction": "IN" for a ZOOM command, but the Direction enum doesn't define IN or OUT values. The enum only includes LEFT, RIGHT, UP, DOWN, FORWARD, BACKWARD, and UNKNOWN. This test would fail because string_to_direction("IN") would return Direction::UNKNOWN. Either add IN and OUT to the Direction enum, or update the test and documentation to use appropriate existing direction values for ZOOM operations.