AeThex-Engine-Core/engine/modules/aethex_ai/ai_assistant.cpp
MrPiglr 9dddce666d
🚀 AeThex Engine v1.0 - Complete Fork
- Forked from Godot Engine 4.7-dev (MIT License)
- Rebranded to AeThex Engine with cyan/purple theme
- Added AI-powered development assistant module
- Integrated Claude API for code completion & error fixing
- Custom hexagon logo and branding
- Multi-platform CI/CD (Windows, Linux, macOS)
- Built Linux editor binary (151MB)
- Complete source code with all customizations

Tech Stack:
- C++ game engine core
- AI Module: Claude 3.5 Sonnet integration
- Build: SCons, 14K+ source files
- License: MIT (Godot) + Custom (AeThex features)

Ready for Windows build via GitHub Actions!
2026-02-23 05:01:56 +00:00

238 lines
6.5 KiB
C++

/**************************************************************************/
/* ai_assistant.cpp */
/**************************************************************************/
#include "ai_assistant.h"
#include "core/config/project_settings.h"
#include "core/io/json.h"
AIAssistant *AIAssistant::singleton = nullptr;
void AIAssistant::_bind_methods() {
// Methods
ClassDB::bind_method(D_METHOD("initialize", "api_key"), &AIAssistant::initialize, DEFVAL(""));
ClassDB::bind_method(D_METHOD("is_initialized"), &AIAssistant::is_initialized);
ClassDB::bind_method(D_METHOD("get_code_completion", "context", "recent_code"), &AIAssistant::get_code_completion);
ClassDB::bind_method(D_METHOD("explain_code", "code_block"), &AIAssistant::explain_code);
ClassDB::bind_method(D_METHOD("fix_error", "error_message", "code_context"), &AIAssistant::fix_error);
ClassDB::bind_method(D_METHOD("generate_function_docs", "function_signature"), &AIAssistant::generate_function_docs);
ClassDB::bind_method(D_METHOD("natural_language_to_code", "description", "context"), &AIAssistant::natural_language_to_code);
ClassDB::bind_method(D_METHOD("set_api_key", "key"), &AIAssistant::set_api_key);
ClassDB::bind_method(D_METHOD("get_api_key"), &AIAssistant::get_api_key);
ClassDB::bind_method(D_METHOD("clear_cache"), &AIAssistant::clear_cache);
// Properties
ADD_PROPERTY(PropertyInfo(Variant::STRING, "api_key", PROPERTY_HINT_PASSWORD), "set_api_key", "get_api_key");
// Enums
BIND_ENUM_CONSTANT(COMPLETION_TYPE_CODE);
BIND_ENUM_CONSTANT(COMPLETION_TYPE_DOCUMENTATION);
BIND_ENUM_CONSTANT(COMPLETION_TYPE_EXPLANATION);
BIND_ENUM_CONSTANT(COMPLETION_TYPE_FIX);
}
Error AIAssistant::initialize(const String &p_api_key) {
if (initialized) {
return OK;
}
// Set API key
if (!p_api_key.is_empty()) {
api_key = p_api_key;
} else {
// Try to get from project settings or environment
if (ProjectSettings::get_singleton()->has_setting("aethex/ai/api_key")) {
api_key = ProjectSettings::get_singleton()->get_setting("aethex/ai/api_key");
}
}
if (api_key.is_empty()) {
ERR_PRINT("AIAssistant: No API key provided. Set it via initialize() or project settings.");
return ERR_UNCONFIGURED;
}
// Initialize API client
api_client.instantiate();
api_client->set_api_key(api_key);
Error err = api_client->initialize();
if (err != OK) {
ERR_PRINT("AIAssistant: Failed to initialize API client.");
return err;
}
initialized = true;
print_line("AIAssistant initialized successfully!");
return OK;
}
String AIAssistant::get_code_completion(const String &p_context, const PackedStringArray &p_recent_code) {
if (!initialized) {
ERR_PRINT("AIAssistant: Not initialized. Call initialize() first.");
return "";
}
// Build prompt
String prompt = "You are an expert GDScript developer. Complete the following code:\n\n";
// Add recent code context
if (p_recent_code.size() > 0) {
prompt += "Recent code:\n";
for (int i = 0; i < p_recent_code.size(); i++) {
prompt += p_recent_code[i] + "\n";
}
prompt += "\n";
}
prompt += "Current context:\n" + p_context + "\n\n";
prompt += "Provide only the code completion, no explanations:";
// Check cache
String cached = _get_cached_response(prompt);
if (!cached.is_empty()) {
return cached;
}
// Make API call (sync for now)
String response = api_client->send_completion_sync(prompt, 5.0);
// Cache the response
if (!response.is_empty()) {
_cache_response(prompt, response);
}
return response;
}
String AIAssistant::explain_code(const String &p_code_block) {
if (!initialized) {
return "";
}
String prompt = "Explain this GDScript code clearly and concisely:\n\n";
prompt += p_code_block;
String cached = _get_cached_response(prompt);
if (!cached.is_empty()) {
return cached;
}
String response = api_client->send_completion_sync(prompt, 10.0);
if (!response.is_empty()) {
_cache_response(prompt, response);
}
return response;
}
String AIAssistant::fix_error(const String &p_error_message, const String &p_code_context) {
if (!initialized) {
return "";
}
String prompt = "Fix this GDScript error. Provide the corrected code:\n\n";
prompt += "Error: " + p_error_message + "\n\n";
prompt += "Code:\n" + p_code_context;
String response = api_client->send_completion_sync(prompt, 10.0);
return response;
}
String AIAssistant::generate_function_docs(const String &p_function_signature) {
if (!initialized) {
return "";
}
String prompt = "Generate documentation for this GDScript function:\n\n";
prompt += p_function_signature + "\n\n";
prompt += "Format: Brief description, parameters, returns.";
String cached = _get_cached_response(prompt);
if (!cached.is_empty()) {
return cached;
}
String response = api_client->send_completion_sync(prompt, 5.0);
if (!response.is_empty()) {
_cache_response(prompt, response);
}
return response;
}
String AIAssistant::generate_class_docs(const String &p_class_code) {
if (!initialized) {
return "";
}
String prompt = "Generate complete documentation for this GDScript class:\n\n";
prompt += p_class_code;
String response = api_client->send_completion_sync(prompt, 15.0);
return response;
}
String AIAssistant::natural_language_to_code(const String &p_description, const String &p_context) {
if (!initialized) {
return "";
}
String prompt = "Convert this description to GDScript code:\n\n";
prompt += p_description + "\n\n";
if (!p_context.is_empty()) {
prompt += "Context:\n" + p_context + "\n\n";
}
prompt += "Provide clean, working GDScript code:";
String response = api_client->send_completion_sync(prompt, 10.0);
return response;
}
void AIAssistant::set_api_key(const String &p_key) {
api_key = p_key;
if (api_client.is_valid()) {
api_client->set_api_key(p_key);
}
}
String AIAssistant::get_api_key() const {
return api_key;
}
void AIAssistant::clear_cache() {
response_cache.clear();
print_line("AIAssistant: Cache cleared.");
}
String AIAssistant::_get_cached_response(const String &p_prompt) {
if (response_cache.has(p_prompt)) {
return response_cache[p_prompt];
}
return "";
}
void AIAssistant::_cache_response(const String &p_prompt, const String &p_response) {
// Simple cache with size limit
if (response_cache.size() > 100) {
response_cache.clear(); // Simple eviction
}
response_cache[p_prompt] = p_response;
}
AIAssistant *AIAssistant::get_singleton() {
return singleton;
}
AIAssistant::AIAssistant() {
singleton = this;
}
AIAssistant::~AIAssistant() {
singleton = nullptr;
}