Add comprehensive RAG subsystem with Doxygen documentation [WIP]#18
Add comprehensive RAG subsystem with Doxygen documentation [WIP]#18renecannao merged 18 commits intov3.1-MCP2from
Conversation
These documents serve as blueprints for implementing RAG (Retrieval-Augmented Generation) capabilities in ProxySQL: - schema.sql: Database schema for RAG implementation - rag_ingest.cpp: PoC ingester blueprint to be integrated into ProxySQL - architecture-data-model.md: Data model architecture for RAG - architecture-runtime-retrieval.md: Runtime retrieval architecture - mcp-tools.md: MCP tools integration design - sql-examples.md: SQL usage examples for RAG - embeddings-design.md: Embeddings design for vector search These files will guide the upcoming RAG implementation in ProxySQL.
Adds a complete RAG subsystem to ProxySQL with: - RAG_Tool_Handler implementing all MCP tools for retrieval operations - Database schema with FTS and vector support - FTS, vector, and hybrid search capabilities - Fetch and refetch tools for document/chunk retrieval - Admin tools for monitoring - Configuration variables for RAG parameters - Comprehensive documentation and test scripts Implements v0 deliverables from RAG blueprint: - SQLite schema initialization - Source registry management - MCP tools: search_fts, search_vector, search_hybrid, get_chunks, get_docs, fetch_from_source, admin.stats - Unit/integration tests and examples
- Use public GenAI_Thread embed_documents() method instead of private LLM_Bridge get_text_embedding() - Fix signedness comparison warning in validate_query_length() - Fix JSON ternary operator type mismatch - Remove unused variables to eliminate warnings - Add GloGATH extern declaration
- Fully implemented rag.search_hybrid tool with both fuse and fts_then_vec modes - Added complete filter support across all search tools (source_ids, source_names, doc_ids, post_type_ids, tags_any, tags_all, created_after, created_before, min_score) - Implemented proper score normalization (higher is better) for all search modes - Updated all tool schemas to match blueprint specifications exactly - Added metadata inclusion in search results - Implemented Reciprocal Rank Fusion (RRF) scoring for hybrid search - Enhanced error handling and input validation - Added debug information for hybrid search ranking - Updated documentation and created completion summary This completes the v0 RAG implementation according to the blueprint requirements.
- Enhanced inline Doxygen comments in RAG_Tool_Handler.h and RAG_Tool_Handler.cpp - Added detailed parameter descriptions, return values, and cross-references - Created Doxyfile for documentation generation - Added documentation summary and guidelines - Documented all RAG tools with their schemas and usage patterns - Added security and performance considerations documentation The RAG subsystem is now fully documented with comprehensive Doxygen comments that provide clear guidance for developers working with the codebase.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughThis pull request introduces a complete Retrieval-Augmented Generation (RAG) subsystem for ProxySQL. It adds a new Changes
Sequence Diagram(s)sequenceDiagram
participant Agent as MCP Client<br/>(Agent)
participant Server as ProxySQL<br/>MCP Server
participant RAGHandler as RAG_Tool_Handler
participant VecDB as SQLite<br/>Vector DB
participant Source as Source DB<br/>(Optional)
Agent->>Server: POST /mcp/rag<br/>(tools/call)
Server->>RAGHandler: execute_tool(tool_name, args)
alt Search Operation (FTS/Vector/Hybrid)
RAGHandler->>RAGHandler: validate_k, validate_query_length
RAGHandler->>VecDB: SELECT from rag_fts_chunks<br/>or rag_vec_chunks
VecDB-->>RAGHandler: Ranked results with scores
RAGHandler->>RAGHandler: normalize_score,<br/>apply filtering
RAGHandler-->>Server: JSON response with<br/>results + timing stats
else Fetch Operation (get_chunks/get_docs)
RAGHandler->>VecDB: SELECT from rag_chunks<br/>or rag_documents
VecDB-->>RAGHandler: Content with metadata
RAGHandler-->>Server: JSON with full content
else Admin Operation (stats)
RAGHandler->>VecDB: COUNT queries across<br/>RAG tables
VecDB-->>RAGHandler: Aggregated stats
RAGHandler-->>Server: JSON statistics
else Authoritative Fetch (fetch_from_source)
RAGHandler->>Source: SELECT with limits
Source-->>RAGHandler: Authoritative row data
RAGHandler-->>Server: JSON with source data
end
Server-->>Agent: JSON-RPC 2.0 Result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes The changes introduce a substantial new subsystem with dense core logic (~2,487 lines in RAG_Tool_Handler.cpp implementing seven tools with sophisticated search/ranking algorithms), multiple integration points across MCP infrastructure (MCP_Thread, ProxySQL_MCP_Server, AI_Features_Manager), comprehensive database schema changes, configuration extensions, and heterogeneous file modifications (code, tests, documentation, PoC). Careful review required for search semantics, scoring normalization (RRF fusion), result filtering logic, and proper lifecycle management across components. Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Summary of ChangesHello @renecannao, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request delivers a fully implemented Retrieval-Augmented Generation (RAG) subsystem for ProxySQL, designed to enhance the capabilities of LLM agents. It provides a robust framework for managing and querying knowledge bases, enabling efficient and accurate information retrieval. The integration includes a new set of MCP tools, a dedicated SQLite database schema, and extensive documentation, ensuring the system is ready for integration testing and future extensions. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive RAG subsystem, a significant and well-structured addition. The implementation includes new database schemas, MCP tools, configurations, and extensive documentation. While the overall design is solid, I have identified several critical and high-severity issues that require attention. Specifically, there are multiple SQL injection vulnerabilities in lib/RAG_Tool_Handler.cpp due to unsafe string concatenation for building SQL queries. Additionally, new RAG configuration variables are not handled in the corresponding get_variable and set_variable methods, rendering them non-configurable at runtime. The embedding dimension is also hardcoded during schema creation. I've also pointed out some medium-severity issues related to code duplication and project structure that would improve maintainability. Addressing these issues will greatly enhance the security and robustness of the new RAG subsystem.
| "rag_enabled", | ||
| "rag_k_max", | ||
| "rag_candidates_max", | ||
| "rag_query_max_bytes", | ||
| "rag_response_max_bytes", | ||
| "rag_timeout_ms", |
There was a problem hiding this comment.
The new RAG configuration variables have been added to the genai_thread_variables_names array and initialized in the constructor, but they are not handled in the get_variable and set_variable methods of the GenAI_Threads_Handler class. This means these settings cannot be viewed or changed at runtime via the admin interface, making them effectively hardcoded to their default values. You need to add the corresponding logic to both get_variable and set_variable for all the new RAG variables.
| "FROM rag_fts_chunks f " | ||
| "JOIN rag_chunks c ON c.chunk_id = f.chunk_id " | ||
| "JOIN rag_documents d ON d.doc_id = c.doc_id " | ||
| "WHERE f MATCH '" + query + "'"; |
There was a problem hiding this comment.
This line, and many others in this file that construct SQL queries, are vulnerable to SQL injection. The query variable, which comes from user input, is directly concatenated into the SQL string. An attacker could provide a malicious string (e.g., containing a single quote) to break out of the string literal and execute arbitrary SQL commands.
This vulnerability pattern is repeated for other parameters like chunk_ids, doc_ids, and filter values (tags_any, created_after, etc.) throughout the execute_tool function.
All user-provided input should be treated as untrusted. Instead of string concatenation, you must use prepared statements with parameter binding to safely construct your SQL queries. This is a critical security issue.
| } | ||
| sql += " FROM `" + s.table_name + "`"; | ||
| if (!s.where_sql.empty()) { | ||
| sql += " WHERE " + s.where_sql; |
There was a problem hiding this comment.
There is a potential SQL injection vulnerability here. The where_sql string, which is read from the rag_sources table, is directly concatenated into the SQL query. If an attacker can control the content of the rag_sources table, they could inject arbitrary SQL. While this table might be admin-controlled, it's a security risk that should be mitigated. The where_sql clause should be validated or constructed in a safer manner.
lib/AI_Features_Manager.cpp
Outdated
| // rag_vec_chunks: sqlite3-vec index | ||
| const char* create_rag_vec_chunks = | ||
| "CREATE VIRTUAL TABLE IF NOT EXISTS rag_vec_chunks USING vec0(" | ||
| "embedding float(1536), " |
There was a problem hiding this comment.
The embedding dimension is hardcoded to 1536. This should be configurable, ideally using the genai_vector_dimension global variable. Hardcoding this value prevents users from using different embedding models with different dimensions without changing the source code.
You should construct the SQL string dynamically to include the configured dimension.
embedding float(%d),
Doxyfile
Outdated
| DOT_TRANSPARENT = NO | ||
| DOT_MULTI_TARGETS = NO | ||
| GENERATE_LEGEND = YES | ||
| DOT_CLEANUP = YES No newline at end of file |
| @@ -0,0 +1,130 @@ | |||
| # ProxySQL RAG Subsystem Implementation - Complete | |||
| json filters = json::object(); | ||
| if (arguments.contains("filters") && arguments["filters"].is_object()) { | ||
| filters = arguments["filters"]; | ||
|
|
||
| // Validate filter parameters | ||
| if (filters.contains("source_ids") && !filters["source_ids"].is_array()) { | ||
| return create_error_response("Invalid source_ids filter: must be an array of integers"); | ||
| } | ||
|
|
||
| if (filters.contains("source_names") && !filters["source_names"].is_array()) { | ||
| return create_error_response("Invalid source_names filter: must be an array of strings"); | ||
| } | ||
|
|
||
| if (filters.contains("doc_ids") && !filters["doc_ids"].is_array()) { | ||
| return create_error_response("Invalid doc_ids filter: must be an array of strings"); | ||
| } | ||
|
|
||
| if (filters.contains("post_type_ids") && !filters["post_type_ids"].is_array()) { | ||
| return create_error_response("Invalid post_type_ids filter: must be an array of integers"); | ||
| } | ||
|
|
||
| if (filters.contains("tags_any") && !filters["tags_any"].is_array()) { | ||
| return create_error_response("Invalid tags_any filter: must be an array of strings"); | ||
| } | ||
|
|
||
| if (filters.contains("tags_all") && !filters["tags_all"].is_array()) { | ||
| return create_error_response("Invalid tags_all filter: must be an array of strings"); | ||
| } | ||
|
|
||
| if (filters.contains("created_after") && !filters["created_after"].is_string()) { | ||
| return create_error_response("Invalid created_after filter: must be a string in ISO 8601 format"); | ||
| } | ||
|
|
||
| if (filters.contains("created_before") && !filters["created_before"].is_string()) { | ||
| return create_error_response("Invalid created_before filter: must be a string in ISO 8601 format"); | ||
| } | ||
|
|
||
| if (filters.contains("min_score") && !(filters["min_score"].is_number() || filters["min_score"].is_string())) { | ||
| return create_error_response("Invalid min_score filter: must be a number or numeric string"); | ||
| } | ||
| } | ||
|
|
||
| // Get return parameters | ||
| bool include_title = true; | ||
| bool include_metadata = true; | ||
| bool include_snippets = false; | ||
| if (arguments.contains("return") && arguments["return"].is_object()) { | ||
| const json& return_params = arguments["return"]; | ||
| include_title = get_json_bool(return_params, "include_title", true); | ||
| include_metadata = get_json_bool(return_params, "include_metadata", true); | ||
| include_snippets = get_json_bool(return_params, "include_snippets", false); | ||
| } | ||
|
|
||
| if (!validate_query_length(query)) { | ||
| return create_error_response("Query too long"); | ||
| } | ||
|
|
||
| // Build FTS query with filters | ||
| std::string sql = "SELECT c.chunk_id, c.doc_id, c.source_id, " | ||
| "(SELECT name FROM rag_sources WHERE source_id = c.source_id) as source_name, " | ||
| "c.title, bm25(f) as score_fts_raw, " | ||
| "c.metadata_json, c.body " | ||
| "FROM rag_fts_chunks f " | ||
| "JOIN rag_chunks c ON c.chunk_id = f.chunk_id " | ||
| "JOIN rag_documents d ON d.doc_id = c.doc_id " | ||
| "WHERE f MATCH '" + query + "'"; | ||
|
|
||
| // Apply filters | ||
| if (filters.contains("source_ids") && filters["source_ids"].is_array()) { | ||
| std::vector<int> source_ids = get_json_int_array(filters, "source_ids"); | ||
| if (!source_ids.empty()) { | ||
| std::string source_list = ""; | ||
| for (size_t i = 0; i < source_ids.size(); ++i) { | ||
| if (i > 0) source_list += ","; | ||
| source_list += std::to_string(source_ids[i]); | ||
| } | ||
| sql += " AND c.source_id IN (" + source_list + ")"; | ||
| } | ||
| } | ||
|
|
||
| if (filters.contains("source_names") && filters["source_names"].is_array()) { | ||
| std::vector<std::string> source_names = get_json_string_array(filters, "source_names"); | ||
| if (!source_names.empty()) { | ||
| std::string source_list = ""; | ||
| for (size_t i = 0; i < source_names.size(); ++i) { | ||
| if (i > 0) source_list += ","; | ||
| source_list += "'" + source_names[i] + "'"; | ||
| } | ||
| sql += " AND c.source_id IN (SELECT source_id FROM rag_sources WHERE name IN (" + source_list + "))"; | ||
| } | ||
| } | ||
|
|
||
| if (filters.contains("doc_ids") && filters["doc_ids"].is_array()) { | ||
| std::vector<std::string> doc_ids = get_json_string_array(filters, "doc_ids"); | ||
| if (!doc_ids.empty()) { | ||
| std::string doc_list = ""; | ||
| for (size_t i = 0; i < doc_ids.size(); ++i) { | ||
| if (i > 0) doc_list += ","; | ||
| doc_list += "'" + doc_ids[i] + "'"; | ||
| } | ||
| sql += " AND c.doc_id IN (" + doc_list + ")"; | ||
| } | ||
| } | ||
|
|
||
| // Metadata filters | ||
| if (filters.contains("post_type_ids") && filters["post_type_ids"].is_array()) { | ||
| std::vector<int> post_type_ids = get_json_int_array(filters, "post_type_ids"); | ||
| if (!post_type_ids.empty()) { | ||
| // Filter by PostTypeId in metadata_json | ||
| std::string post_type_conditions = ""; | ||
| for (size_t i = 0; i < post_type_ids.size(); ++i) { | ||
| if (i > 0) post_type_conditions += " OR "; | ||
| post_type_conditions += "json_extract(d.metadata_json, '$.PostTypeId') = " + std::to_string(post_type_ids[i]); | ||
| } | ||
| sql += " AND (" + post_type_conditions + ")"; | ||
| } | ||
| } | ||
|
|
||
| if (filters.contains("tags_any") && filters["tags_any"].is_array()) { | ||
| std::vector<std::string> tags_any = get_json_string_array(filters, "tags_any"); | ||
| if (!tags_any.empty()) { | ||
| // Filter by any of the tags in metadata_json Tags field | ||
| std::string tag_conditions = ""; | ||
| for (size_t i = 0; i < tags_any.size(); ++i) { | ||
| if (i > 0) tag_conditions += " OR "; | ||
| tag_conditions += "json_extract(d.metadata_json, '$.Tags') LIKE '%<" + tags_any[i] + ">%'"; | ||
| } | ||
| sql += " AND (" + tag_conditions + ")"; | ||
| } | ||
| } | ||
|
|
||
| if (filters.contains("tags_all") && filters["tags_all"].is_array()) { | ||
| std::vector<std::string> tags_all = get_json_string_array(filters, "tags_all"); | ||
| if (!tags_all.empty()) { | ||
| // Filter by all of the tags in metadata_json Tags field | ||
| std::string tag_conditions = ""; | ||
| for (size_t i = 0; i < tags_all.size(); ++i) { | ||
| if (i > 0) tag_conditions += " AND "; | ||
| tag_conditions += "json_extract(d.metadata_json, '$.Tags') LIKE '%<" + tags_all[i] + ">%'"; | ||
| } | ||
| sql += " AND (" + tag_conditions + ")"; | ||
| } | ||
| } | ||
|
|
||
| if (filters.contains("created_after") && filters["created_after"].is_string()) { | ||
| std::string created_after = filters["created_after"].get<std::string>(); | ||
| // Filter by CreationDate in metadata_json | ||
| sql += " AND json_extract(d.metadata_json, '$.CreationDate') >= '" + created_after + "'"; | ||
| } | ||
|
|
||
| if (filters.contains("created_before") && filters["created_before"].is_string()) { | ||
| std::string created_before = filters["created_before"].get<std::string>(); | ||
| // Filter by CreationDate in metadata_json | ||
| sql += " AND json_extract(d.metadata_json, '$.CreationDate') <= '" + created_before + "'"; | ||
| } |
There was a problem hiding this comment.
The code for building the SQL WHERE clause based on filters is duplicated across rag.search_fts, rag.search_vector, and rag.search_hybrid. This makes the code harder to maintain and prone to errors, as a bug fix or change in one place might need to be manually replicated in others.
Consider refactoring this logic into a separate helper function that takes the filters JSON object and a string builder as input, and appends the appropriate SQL conditions. This would centralize the filter handling logic, reduce code duplication, and improve maintainability.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Pull request overview
This pull request implements a comprehensive RAG (Retrieval-Augmented Generation) subsystem for ProxySQL with full MCP (Model Context Protocol) integration. The implementation provides semantic search capabilities combining FTS5 keyword search and vector embeddings with hybrid ranking strategies.
Changes:
- Complete RAG Tool Handler with 7 MCP tools for search, fetch, and admin operations
- Database integration with 7-table RAG schema supporting FTS5 and sqlite3-vec
- Configuration system with 6 runtime-configurable RAG parameters
- Security features including input validation, query limits, and timeouts
- Comprehensive test scripts and Doxygen documentation
Reviewed changes
Copilot reviewed 32 out of 32 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/RAG_Tool_Handler.cpp | Core RAG implementation with search, fetch, and admin tools |
| include/RAG_Tool_Handler.h | RAG handler class definition with comprehensive documentation |
| lib/AI_Features_Manager.cpp | RAG database schema creation with 7 tables and indexes |
| lib/ProxySQL_MCP_Server.cpp | RAG endpoint registration at /mcp/rag |
| lib/MCP_Thread.cpp | RAG handler lifecycle management |
| lib/GenAI_Thread.cpp | RAG configuration variable initialization |
| test/test_rag_schema.cpp | Schema validation test for RAG tables and views |
| scripts/mcp/test_rag.sh | Functional tests for RAG MCP endpoint |
| doc/rag-*.md | Comprehensive documentation and examples |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Forward declaration for GloGATH | ||
| extern GenAI_Threads_Handler *GloGATH; | ||
|
|
There was a problem hiding this comment.
Duplicate forward declaration and extern statement for GloGATH. The forward declaration appears at line 33 and again at line 41. This duplication should be removed to improve code maintainability.
| // Forward declaration for GloGATH | |
| extern GenAI_Threads_Handler *GloGATH; |
lib/RAG_Tool_Handler.cpp
Outdated
| std::string sql = "SELECT c.chunk_id, c.doc_id, c.source_id, " | ||
| "(SELECT name FROM rag_sources WHERE source_id = c.source_id) as source_name, " | ||
| "c.title, bm25(f) as score_fts_raw, " | ||
| "c.metadata_json, c.body " | ||
| "FROM rag_fts_chunks f " | ||
| "JOIN rag_chunks c ON c.chunk_id = f.chunk_id " | ||
| "JOIN rag_documents d ON d.doc_id = c.doc_id " | ||
| "WHERE f MATCH '" + query + "'"; | ||
|
|
||
| // Apply filters | ||
| if (filters.contains("source_ids") && filters["source_ids"].is_array()) { | ||
| std::vector<int> source_ids = get_json_int_array(filters, "source_ids"); | ||
| if (!source_ids.empty()) { | ||
| std::string source_list = ""; | ||
| for (size_t i = 0; i < source_ids.size(); ++i) { | ||
| if (i > 0) source_list += ","; | ||
| source_list += std::to_string(source_ids[i]); | ||
| } | ||
| sql += " AND c.source_id IN (" + source_list + ")"; | ||
| } | ||
| } | ||
|
|
||
| if (filters.contains("source_names") && filters["source_names"].is_array()) { | ||
| std::vector<std::string> source_names = get_json_string_array(filters, "source_names"); | ||
| if (!source_names.empty()) { | ||
| std::string source_list = ""; | ||
| for (size_t i = 0; i < source_names.size(); ++i) { | ||
| if (i > 0) source_list += ","; | ||
| source_list += "'" + source_names[i] + "'"; | ||
| } | ||
| sql += " AND c.source_id IN (SELECT source_id FROM rag_sources WHERE name IN (" + source_list + "))"; | ||
| } | ||
| } | ||
|
|
||
| if (filters.contains("doc_ids") && filters["doc_ids"].is_array()) { | ||
| std::vector<std::string> doc_ids = get_json_string_array(filters, "doc_ids"); | ||
| if (!doc_ids.empty()) { | ||
| std::string doc_list = ""; | ||
| for (size_t i = 0; i < doc_ids.size(); ++i) { | ||
| if (i > 0) doc_list += ","; | ||
| doc_list += "'" + doc_ids[i] + "'"; | ||
| } | ||
| sql += " AND c.doc_id IN (" + doc_list + ")"; |
There was a problem hiding this comment.
Potential SQL injection vulnerability. The query strings are constructed by concatenating user input without proper sanitization or parameterized queries. For example, source_names and doc_ids are directly concatenated into SQL strings. Consider using prepared statements with parameter binding for all user-provided values to prevent SQL injection attacks.
| │ │ ┌─────────────┐ │ │ | ||
| │ │ │ /rag │ │ │ | ||
| │ │ │ endpoint │ │ │ | ||
| │ │ └─────────────┘ │ │ |
There was a problem hiding this comment.
ASCII art in diagram has formatting issues. Lines 51-54 show misaligned box drawing characters where pipes and corners don't properly close the diagram boxes. This appears to be a visual representation issue that should be corrected for better readability.
| │ │ ┌─────────────┐ │ │ | |
| │ │ │ /rag │ │ │ | |
| │ │ │ endpoint │ │ │ | |
| │ │ └─────────────┘ │ │ | |
| │ │ ┌─────────────┐ │ │ | |
| │ │ │ /rag │ │ │ | |
| │ │ │ endpoint │ │ │ | |
| │ │ └─────────────┘ │ │ |
There was a problem hiding this comment.
Actionable comments posted: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/GenAI_Thread.cpp (1)
1375-1378: Critical:lock.release()causes deadlock.
lock.release()releases ownership of the mutex without unlocking it, causing the mutex to remain locked forever. Subsequent requests will deadlock waiting forqueue_mutex_.Proposed fix
GenAI_Request req = std::move(request_queue_.front()); request_queue_.pop(); - lock.release(); + lock.unlock();
🤖 Fix all issues with AI agents
In `@doc/RAG_Tool_Handler.cpp.doxygen`:
- Around line 22-31: The file contains two identical forward declarations of the
global pointer symbol GloGATH (extern GenAI_Threads_Handler *GloGATH;); remove
the redundant declaration so only a single forward declaration of GloGATH
remains (keep one instance and delete the other) to eliminate duplication while
preserving the forward declaration for GenAI_Threads_Handler and GloGATH.
In `@doc/rag-documentation.md`:
- Around line 17-28: Replace the incorrect ProxySQL dot-notation variables with
the hyphen-prefixed admin variable names used by ProxySQL: change genai.enabled
to genai-enabled, genai.rag_enabled to genai-rag_enabled, and update the
parameter names accordingly (genai.rag_k_max → genai-rag_k_max,
genai.rag_candidates_max → genai-rag_candidates_max, genai.rag_timeout_ms →
genai-rag_timeout_ms) in the SQL examples so the SET statements use the correct
ProxySQL variable names.
In `@lib/RAG_Tool_Handler.cpp`:
- Around line 32-41: Remove the duplicate forward declaration of the global
pointer GloGATH: keep a single declaration of "extern GenAI_Threads_Handler
*GloGATH;" in lib/RAG_Tool_Handler.cpp and delete the redundant one so the
symbol is only declared once.
- Around line 1401-1422: The w_fts and w_vec doubles are being read with
get_json_int (truncating fractional values); add a helper
RAG_Tool_Handler::get_json_double(const json&, const std::string&, double) that
safely extracts numbers/strings to double (with fallback to default and error
handling), then replace the two get_json_int calls for w_fts and w_vec in both
the fuse_params branch and the fallback branch with get_json_double, leaving
validate_k and rrf_k0 extraction unchanged.
In `@RAG_COMPLETION_SUMMARY.md`:
- Around line 3-5: Update the summary wording in RAG_COMPLETION_SUMMARY.md to
reflect the PR's WIP state: replace the header string "Status: COMPLETE" with
"Status: WIP / pending integration testing" and change any phrases that assert
production readiness (e.g., "ready for production use") to a softer phrasing
such as "not yet ready for production; pending integration testing"; apply these
edits to the occurrences around the top block and the repeated lines referenced
(the other occurrence at lines 84-85).
In `@RAG_IMPLEMENTATION_COMPLETE.md`:
- Around line 3-6: Change the status header "## Implementation Status: COMPLETE"
to reflect ongoing work—e.g., "## Implementation Status: IN PROGRESS
(integration testing pending)"—and update any leading sentences in the
RAG_IMPLEMENTATION_COMPLETE.md that claim full completion to note that
integration testing and validation are still pending; search for the header
string and any occurrences of "COMPLETE" in the file to make the consistent
wording change.
In `@RAG_POC/rag_ingest.cpp`:
- Around line 686-698: The assignments use direct (const
char*)sqlite3_column_text(...) which can produce undefined behavior if NULL;
update the mapping for s.backend_type, s.host, s.user, s.pass, s.db,
s.table_name, s.pk_column and s.where_sql to use the existing str_or_empty(...)
helper (the same defensive pattern already used for s.name) instead of direct
casts so each std::string is constructed safely even when sqlite3_column_text
returns NULL.
In `@RAG_POC/schema.sql`:
- Around line 23-24: The schema currently stores plaintext credentials in the
rag_sources table column backend_pass; replace this with a secure alternative by
either (A) storing an encrypted credential blob (e.g., add
backend_pass_encrypted and remove backend_pass) and implement
encryption/decryption functions using a centrally-managed key, or (B) storing
only a secret reference (e.g., backend_pass_secret_ref) that points to a secrets
manager/vault entry rather than actual secrets; update any code that
reads/writes backend_pass to use the new column and perform
encryption/decryption or vault lookups, add a migration to convert or remove
existing plaintext values, and document the key management/ACL requirements for
the new approach.
In `@scripts/mcp/test_rag.sh`:
- Around line 50-60: The log_success and log_failure functions currently use $@
after a string prefix which triggers shellcheck SC2145; update both functions to
concatenate all arguments as a single string by replacing $@ with "$*" in the
echo lines inside log_success and log_failure (keep the QUIET check and existing
color prefixes intact).
- Line 14: Remove or neutralize the global `set -e` so a single failing test
doesn't abort before the test summary is printed; alternatively replace it with
an error trap that captures the exit code, runs the test-summary routine, then
exits with that code (e.g., trap 'rc=$?; <call your summary function or the
test-summary block>; exit $rc' ERR or use trap on EXIT). Update the script to
invoke the existing summary block (the test summary code in this file) from the
trap so it always runs on failure, or remove `set -e` and ensure `main` or the
test runner explicitly exits after calling the summary.
In `@test/build_rag_test.sh`:
- Around line 46-49: The compile command for test_rag_schema.cpp omits the
SQLite3DB implementation and sqlite3 library, causing undefined references;
update the build step that invokes g++ for test_rag_schema to also link the
SQLite3DB object/compiled file (e.g., lib/sqlite3db.cpp compiled to sqlite3db.o
or the corresponding object) and the sqlite3 library (e.g., -lsqlite3), or call
the existing Makefile target that already builds and links SQLite3DB; ensure
references to SQLite3DB and sqlite3 are included in the g++ link line so
test_rag_schema links successfully.
In `@test/Makefile`:
- Around line 31-32: The test_rag_schema Makefile target references an undefined
variable $(PROXYSQL_OBJS); replace it with the explicit object/library
dependencies used elsewhere (follow the sqlite_history_convert target pattern)
so test_rag_schema links the sqlite-related objects required by
test_rag_schema.cpp (e.g., the sqlite3db-related object files and any other
PROXYSQL libraries already listed via $(PROXYSQL_LIBS)/IDIRS/LDIRS). Update the
test_rag_schema rule to remove $(PROXYSQL_OBJS) and list the same object
files/libraries referenced by sqlite_history_convert so the linker can find the
sqlite3db symbols.
In `@test/test_rag_schema.cpp`:
- Around line 32-34: Replace the hard-coded db_path constant in
test/test_rag_schema.cpp with an environment-variable-driven value: read an env
var (e.g., PROXYSQL_DATADIR or PROXYSQL_AI_DB) via getenv and use that if
present, otherwise fall back to the current default
"/var/lib/proxysql/ai_features.db"; update the code that prints and uses db_path
(the db_path variable and the std::cout line) so tests can be configured by CI
or local environments without changing source.
♻️ Duplicate comments (8)
Doxyfile (1)
249-249: Missing final newline character.The file is missing a trailing newline at the end. This is a standard convention that helps with some text processing tools.
RAG_IMPLEMENTATION_SUMMARY.md (1)
1-5: Consider consolidating withRAG_IMPLEMENTATION_COMPLETE.md.This file appears to cover similar content to
RAG_IMPLEMENTATION_COMPLETE.md. Having duplicate documentation files can lead to maintenance burden and confusion when updates are needed. Consider merging these into a single canonical implementation document.RAG_POC/rag_ingest.cpp (1)
475-477: SQL injection risk viawhere_sqlconcatenation.The
where_sqlvalue fromrag_sourcesis directly concatenated into the SQL query without validation. If an attacker gains write access to therag_sourcestable, they could inject arbitrary SQL.While this is admin-controlled data, consider validating/sanitizing
where_sqlor documenting the trust boundary explicitly.lib/GenAI_Thread.cpp (1)
76-82: RAG variables registered but not accessible via admin interface.The RAG variable names are added to the array, but the corresponding handling is missing in
get_variable()(lines 363-473) andset_variable()(lines 476-657). This means these settings cannot be viewed or changed at runtime.Required additions to get_variable()
Add before
return NULL;at line 473:// RAG configuration if (!strcmp(name, "rag_enabled")) { return strdup(variables.genai_rag_enabled ? "true" : "false"); } if (!strcmp(name, "rag_k_max")) { char buf[64]; sprintf(buf, "%d", variables.genai_rag_k_max); return strdup(buf); } if (!strcmp(name, "rag_candidates_max")) { char buf[64]; sprintf(buf, "%d", variables.genai_rag_candidates_max); return strdup(buf); } if (!strcmp(name, "rag_query_max_bytes")) { char buf[64]; sprintf(buf, "%d", variables.genai_rag_query_max_bytes); return strdup(buf); } if (!strcmp(name, "rag_response_max_bytes")) { char buf[64]; sprintf(buf, "%d", variables.genai_rag_response_max_bytes); return strdup(buf); } if (!strcmp(name, "rag_timeout_ms")) { char buf[64]; sprintf(buf, "%d", variables.genai_rag_timeout_ms); return strdup(buf); }Required additions to set_variable()
Add before
return false;at line 657:// RAG configuration if (!strcmp(name, "rag_enabled")) { variables.genai_rag_enabled = (strcmp(value, "true") == 0); return true; } if (!strcmp(name, "rag_k_max")) { int val = atoi(value); if (val < 1 || val > 1000) { proxy_error("Invalid value for genai_rag_k_max: %d (must be 1-1000)\n", val); return false; } variables.genai_rag_k_max = val; return true; } if (!strcmp(name, "rag_candidates_max")) { int val = atoi(value); if (val < 1 || val > 10000) { proxy_error("Invalid value for genai_rag_candidates_max: %d (must be 1-10000)\n", val); return false; } variables.genai_rag_candidates_max = val; return true; } if (!strcmp(name, "rag_query_max_bytes")) { int val = atoi(value); if (val < 1024 || val > 1048576) { proxy_error("Invalid value for genai_rag_query_max_bytes: %d (must be 1024-1048576)\n", val); return false; } variables.genai_rag_query_max_bytes = val; return true; } if (!strcmp(name, "rag_response_max_bytes")) { int val = atoi(value); if (val < 1024 || val > 100000000) { proxy_error("Invalid value for genai_rag_response_max_bytes: %d (must be 1024-100000000)\n", val); return false; } variables.genai_rag_response_max_bytes = val; return true; } if (!strcmp(name, "rag_timeout_ms")) { int val = atoi(value); if (val < 100 || val > 60000) { proxy_error("Invalid value for genai_rag_timeout_ms: %d (must be 100-60000)\n", val); return false; } variables.genai_rag_timeout_ms = val; return true; }lib/AI_Features_Manager.cpp (1)
300-308: Makerag_vec_chunksembedding dimension configurable (avoid hardcoded 1536).The vec table dimension must match the embedding model. Hardcoding
1536risks insert/search failures when users configure a different model. Use the configured vector dimension (e.g.,genai_vector_dimension) and keep it consistent across vec tables.♻️ Suggested configuration-based DDL
- const char* create_rag_vec_chunks = - "CREATE VIRTUAL TABLE IF NOT EXISTS rag_vec_chunks USING vec0(" - "embedding float(1536), " - "chunk_id TEXT, " - "doc_id TEXT, " - "source_id INTEGER, " - "updated_at INTEGER" - ");"; + char create_rag_vec_chunks[512]; + snprintf(create_rag_vec_chunks, sizeof(create_rag_vec_chunks), + "CREATE VIRTUAL TABLE IF NOT EXISTS rag_vec_chunks USING vec0(" + "embedding float(%d), " + "chunk_id TEXT, " + "doc_id TEXT, " + "source_id INTEGER, " + "updated_at INTEGER" + ");", + GloGATH->variables.genai_vector_dimension);Confirm the configured dimension exists and is used elsewhere:
#!/bin/bash rg -n "genai_vector_dimension" -g'*.h' -g'*.cpp'lib/RAG_Tool_Handler.cpp (3)
901-908: SQL injection vulnerability in FTS query construction.User-provided
queryis directly concatenated into the SQL string without sanitization or parameterization. This allows SQL injection attacks through crafted search queries.This same pattern is repeated throughout the file for
source_names,doc_ids,tags_any,tags_all,created_after,created_before, and similar parameters in other tools.
843-883: Duplicated filter validation and SQL building logic.The filter validation code (checking if arrays are valid, etc.) and SQL WHERE clause construction are duplicated across
rag.search_fts,rag.search_vector, andrag.search_hybrid. This should be refactored into shared helper functions.
2159-2172: SQL injection risk in chunk ID list construction.
chunk_idsfrom user input are directly concatenated into the SQL query. This is part of the broader SQL injection pattern that should be addressed with prepared statements.
🧹 Nitpick comments (6)
RAG_POC/embeddings-design.md (1)
42-47: Consider adding language specifier to fenced code block.The embedding input template example could benefit from a language specifier for consistency. Since this is a text template rather than a specific programming language, you could use
textorplaintext.-``` +```text {Title} Tags: {Tags} {ChunkBody}</blockquote></details> <details> <summary>RAG_POC/schema.sql (1)</summary><blockquote> `134-141`: **Hardcoded embedding dimension requires schema migration for different models.** The `float[1536]` dimension is suitable for OpenAI's text-embedding-3-large, but using a different model (e.g., 768-dim or 3072-dim) requires schema modification. The comment on line 136 acknowledges this. For future flexibility, consider documenting the model-to-dimension mapping or adding a configuration check during ingestion to validate dimension compatibility. </blockquote></details> <details> <summary>RAG_POC/rag_ingest.cpp (1)</summary><blockquote> `901-905`: **`updated_at` always stored as 0 in vector table.** The `now_epoch` is hardcoded to 0 rather than querying `SELECT unixepoch()`. As documented in the comments, this is a v0 simplification. For production use, consider caching a single `unixepoch()` result at the start of each ingestion run. </blockquote></details> <details> <summary>doc/rag-examples.md (1)</summary><blockquote> `7-14`: **Add a brief note about TLS verification and optional auth.** The examples use `-k` and don’t mention endpoint auth. A short note helps avoid insecure copy/paste in production. <details> <summary>✍️ Suggested doc addition</summary> ```diff @@ SET genai.rag_enabled = true; LOAD genai VARIABLES TO RUNTIME;
+> Note: The curl examples use
-kfor local development (skips TLS verification). For production, provide your CA cert (e.g.,--cacert) and any endpoint auth configured for /mcp/rag.</details> </blockquote></details> <details> <summary>lib/AI_Features_Manager.cpp (1)</summary><blockquote> `286-298`: **FTS queries gracefully handle missing `rag_fts_chunks` table via error responses, but consider validating table availability at initialization time for better UX.** The `rag_fts_chunks` table creation failure is non-fatal (line 297 logs and continues), and when FTS queries execute without the table, the code properly handles the missing table scenario by returning an error response to the user ("Database query failed" at lines 1003-1004, 1267-1269). However, users will still encounter runtime errors when calling `rag.search_fts` if the table doesn't exist. Proactively validating RAG table creation during init—or explicitly disabling FTS tools if the table is unavailable—would provide better failure visibility and prevent failed tool invocations. </blockquote></details> <details> <summary>lib/RAG_Tool_Handler.cpp (1)</summary><blockquote> `2356-2366`: **Dead code: extracted but unused variables.** Several variables (`source_id`, `backend_type`, `backend_host`, etc.) are extracted from the query result but immediately commented out. Since this appears to be placeholder code for future database connectivity, consider either removing these lines or adding an explicit TODO comment documenting the planned functionality. <details> <summary>Suggested cleanup</summary> ```diff for (const auto& row : doc_result->rows) { if (row->fields && rows.size() < static_cast<size_t>(max_rows) && total_bytes < max_bytes) { std::string doc_id = row->fields[0] ? row->fields[0] : ""; - // int source_id = row->fields[1] ? std::stoi(row->fields[1]) : 0; std::string pk_json = row->fields[2] ? row->fields[2] : "{}"; std::string source_name = row->fields[3] ? row->fields[3] : ""; - // std::string backend_type = row->fields[4] ? row->fields[4] : ""; - // std::string backend_host = row->fields[5] ? row->fields[5] : ""; - // int backend_port = row->fields[6] ? std::stoi(row->fields[6]) : 0; - // std::string backend_user = row->fields[7] ? row->fields[7] : ""; - // std::string backend_pass = row->fields[8] ? row->fields[8] : ""; - // std::string backend_db = row->fields[9] ? row->fields[9] : ""; - // std::string table_name = row->fields[10] ? row->fields[10] : ""; std::string pk_column = row->fields[11] ? row->fields[11] : ""; + + // TODO: Connect to source database using backend_* fields (rows 4-10) + // to fetch actual data instead of returning mock values.
doc/RAG_Tool_Handler.cpp.doxygen
Outdated
| // Forward declaration for GloGATH | ||
| extern GenAI_Threads_Handler *GloGATH; | ||
|
|
||
| // JSON library | ||
| #include "../deps/json/json.hpp" | ||
| using json = nlohmann::json; | ||
| #define PROXYJSON | ||
|
|
||
| // Forward declaration for GloGATH | ||
| extern GenAI_Threads_Handler *GloGATH; |
There was a problem hiding this comment.
Duplicate forward declaration of GloGATH.
The forward declaration extern GenAI_Threads_Handler *GloGATH; appears twice (lines 22-23 and 30-31). Remove one of them to clean up the documentation.
Suggested fix
// Forward declaration for GloGATH
extern GenAI_Threads_Handler *GloGATH;
// JSON library
`#include` "../deps/json/json.hpp"
using json = nlohmann::json;
`#define` PROXYJSON
-
-// Forward declaration for GloGATH
-extern GenAI_Threads_Handler *GloGATH;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Forward declaration for GloGATH | |
| extern GenAI_Threads_Handler *GloGATH; | |
| // JSON library | |
| #include "../deps/json/json.hpp" | |
| using json = nlohmann::json; | |
| #define PROXYJSON | |
| // Forward declaration for GloGATH | |
| extern GenAI_Threads_Handler *GloGATH; | |
| // Forward declaration for GloGATH | |
| extern GenAI_Threads_Handler *GloGATH; | |
| // JSON library | |
| `#include` "../deps/json/json.hpp" | |
| using json = nlohmann::json; | |
| `#define` PROXYJSON |
🤖 Prompt for AI Agents
In `@doc/RAG_Tool_Handler.cpp.doxygen` around lines 22 - 31, The file contains two
identical forward declarations of the global pointer symbol GloGATH (extern
GenAI_Threads_Handler *GloGATH;); remove the redundant declaration so only a
single forward declaration of GloGATH remains (keep one instance and delete the
other) to eliminate duplication while preserving the forward declaration for
GenAI_Threads_Handler and GloGATH.
| ```sql | ||
| -- Enable GenAI module | ||
| SET genai.enabled = true; | ||
|
|
||
| -- Enable RAG features | ||
| SET genai.rag_enabled = true; | ||
|
|
||
| -- Configure RAG parameters (optional) | ||
| SET genai.rag_k_max = 50; | ||
| SET genai.rag_candidates_max = 500; | ||
| SET genai.rag_timeout_ms = 2000; | ||
| ``` |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, let's understand the repository structure and find relevant files
echo "=== Repository structure ==="
find . -type f -name "*.md" | head -20
echo ""
echo "=== Files mentioning ProxySQL or genai ==="
rg -l "ProxySQL|genai" --type md | head -20Repository: ProxySQL/proxysql-vec
Length of output: 1223
🏁 Script executed:
#!/bin/bash
# Check the full RAG documentation context
echo "=== RAG documentation around lines 17-28 ==="
sed -n '1,50p' doc/rag-documentation.mdRepository: ProxySQL/proxysql-vec
Length of output: 1299
🏁 Script executed:
#!/bin/bash
# Look for any configuration or setup files that show how these variables are actually used
echo "=== Files mentioning genai configuration ==="
rg "genai\." --type sh --type py --type sql | head -30Repository: ProxySQL/proxysql-vec
Length of output: 109
🏁 Script executed:
#!/bin/bash
# Search for ProxySQL variable naming patterns in codebase
echo "=== ProxySQL variable patterns ==="
rg "SET.*=" --type sql | grep -v "SELECT" | head -20Repository: ProxySQL/proxysql-vec
Length of output: 495
🏁 Script executed:
#!/bin/bash
# Search for how genai variables are actually referenced in the codebase
echo "=== Looking for genai variable definitions ==="
rg "genai" --type cpp --type c | grep -i "variable\|set\|enable" | head -30Repository: ProxySQL/proxysql-vec
Length of output: 3472
🏁 Script executed:
#!/bin/bash
# Check if there's a configuration guide or admin setup documentation
echo "=== Configuration or variable documentation ==="
find . -type f \( -name "*.md" -o -name "*.txt" \) | xargs grep -l "genai\|variable.*name" | head -10Repository: ProxySQL/proxysql-vec
Length of output: 384
🏁 Script executed:
#!/bin/bash
# Look at the genai_prototype directory to understand how GenAI is implemented
echo "=== GenAI prototype files ==="
ls -la genai_prototype/ 2>/dev/null | head -20
cat genai_prototype/README.md 2>/dev/null | head -100Repository: ProxySQL/proxysql-vec
Length of output: 3962
🏁 Script executed:
#!/bin/bash
# Search for any configuration parsing or admin command handling
echo "=== Admin configuration handling ==="
rg "admin.*genai|genai.*admin" --type cpp --type c | head -20Repository: ProxySQL/proxysql-vec
Length of output: 1859
🏁 Script executed:
#!/bin/bash
# Check if genai variables are documented elsewhere or in code comments
echo "=== GenAI variable documentation in code ==="
rg "genai\.enabled|genai\.rag" --type cpp --type c --type h | head -30Repository: ProxySQL/proxysql-vec
Length of output: 109
🏁 Script executed:
#!/bin/bash
# Check the GENAI.md documentation for the correct syntax
echo "=== GENAI.md documentation ==="
cat doc/GENAI.md 2>/dev/null | head -80Repository: ProxySQL/proxysql-vec
Length of output: 3083
🏁 Script executed:
#!/bin/bash
# Check MCP VARIABLES documentation
echo "=== MCP VARIABLES.md documentation ==="
cat doc/MCP/VARIABLES.md 2>/dev/null | head -100Repository: ProxySQL/proxysql-vec
Length of output: 2908
🏁 Script executed:
#!/bin/bash
# Get more context from test files showing actual usage
echo "=== Actual test usage of genai variables ==="
sed -n '1,200p' test/tap/tests/genai_module-t.cpp | grep -A2 "SET genai"Repository: ProxySQL/proxysql-vec
Length of output: 1174
🏁 Script executed:
#!/bin/bash
# Search for any RAG-specific variable documentation
echo "=== RAG variable references ==="
rg "rag_enabled|rag-enabled|rag\.enabled" --type md --type cppRepository: ProxySQL/proxysql-vec
Length of output: 906
🏁 Script executed:
#!/bin/bash
# Check if there's a RAG configuration documentation file
echo "=== RAG configuration files ==="
find . -type f -name "*rag*" | grep -E "\.(md|txt|sql)$"Repository: ProxySQL/proxysql-vec
Length of output: 223
🏁 Script executed:
#!/bin/bash
# Search for where RAG variables are actually defined/implemented
echo "=== GenAI variable definitions in code ==="
rg "rag_enabled|rag-enabled" --type cpp --type h | head -40Repository: ProxySQL/proxysql-vec
Length of output: 309
🏁 Script executed:
#!/bin/bash
# Check the actual variable names used in admin interface
echo "=== Variable naming patterns in Admin_FlushVariables ==="
sed -n '1,100p' lib/Admin_FlushVariables.cpp | grep -A5 -B5 "genai"Repository: ProxySQL/proxysql-vec
Length of output: 121
🏁 Script executed:
#!/bin/bash
# Check for any dot notation support in the admin interface
echo "=== Checking for dot notation in variable handling ==="
rg "variable_name.*\." --type cpp | grep -i genai | head -20Repository: ProxySQL/proxysql-vec
Length of output: 119
🏁 Script executed:
#!/bin/bash
# Look at how variables are actually parsed in admin interface
echo "=== Variable name parsing in ProxySQL ==="
rg "SET.*=" --type cpp | grep -i "variable\|genai" | head -20Repository: ProxySQL/proxysql-vec
Length of output: 3374
🏁 Script executed:
#!/bin/bash
# Check all documentation files for consistency in genai variable syntax
echo "=== GenAI syntax across all documentation ==="
grep -r "SET genai" doc/ | grep -v "Binary"Repository: ProxySQL/proxysql-vec
Length of output: 3767
🏁 Script executed:
#!/bin/bash
# Check the actual genai variable names in GenAI_Thread.cpp
echo "=== Variable name definitions in GenAI_Thread.cpp ==="
sed -n '1,300p' lib/GenAI_Thread.cpp | grep -A5 "rag_enabled\|enabled"Repository: ProxySQL/proxysql-vec
Length of output: 1344
Fix ProxySQL SET syntax for GenAI variables in configuration examples.
The documentation uses incorrect dot notation (SET genai.enabled = true) for ProxySQL variables. ProxySQL admin interface uses hyphen-prefixed variable names. The correct syntax should be:
-- Enable GenAI module
SET genai-enabled = true;
-- Enable RAG features
SET genai-rag_enabled = true;
-- Configure RAG parameters (optional)
SET genai-rag_k_max = 50;
SET genai-rag_candidates_max = 500;
SET genai-rag_timeout_ms = 2000;This matches the syntax used consistently across other GenAI documentation and all test code in the repository.
🤖 Prompt for AI Agents
In `@doc/rag-documentation.md` around lines 17 - 28, Replace the incorrect
ProxySQL dot-notation variables with the hyphen-prefixed admin variable names
used by ProxySQL: change genai.enabled to genai-enabled, genai.rag_enabled to
genai-rag_enabled, and update the parameter names accordingly (genai.rag_k_max →
genai-rag_k_max, genai.rag_candidates_max → genai-rag_candidates_max,
genai.rag_timeout_ms → genai-rag_timeout_ms) in the SQL examples so the SET
statements use the correct ProxySQL variable names.
| // Forward declaration for GloGATH | ||
| extern GenAI_Threads_Handler *GloGATH; | ||
|
|
||
| // JSON library | ||
| #include "../deps/json/json.hpp" | ||
| using json = nlohmann::json; | ||
| #define PROXYJSON | ||
|
|
||
| // Forward declaration for GloGATH | ||
| extern GenAI_Threads_Handler *GloGATH; |
There was a problem hiding this comment.
Duplicate forward declaration of GloGATH.
The forward declaration appears twice at lines 32-33 and 40-41. Remove the duplicate.
Suggested fix
// Forward declaration for GloGATH
extern GenAI_Threads_Handler *GloGATH;
// JSON library
`#include` "../deps/json/json.hpp"
using json = nlohmann::json;
`#define` PROXYJSON
-
-// Forward declaration for GloGATH
-extern GenAI_Threads_Handler *GloGATH;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Forward declaration for GloGATH | |
| extern GenAI_Threads_Handler *GloGATH; | |
| // JSON library | |
| #include "../deps/json/json.hpp" | |
| using json = nlohmann::json; | |
| #define PROXYJSON | |
| // Forward declaration for GloGATH | |
| extern GenAI_Threads_Handler *GloGATH; | |
| // Forward declaration for GloGATH | |
| extern GenAI_Threads_Handler *GloGATH; | |
| // JSON library | |
| `#include` "../deps/json/json.hpp" | |
| using json = nlohmann::json; | |
| `#define` PROXYJSON |
🤖 Prompt for AI Agents
In `@lib/RAG_Tool_Handler.cpp` around lines 32 - 41, Remove the duplicate forward
declaration of the global pointer GloGATH: keep a single declaration of "extern
GenAI_Threads_Handler *GloGATH;" in lib/RAG_Tool_Handler.cpp and delete the
redundant one so the symbol is only declared once.
| // Get FTS parameters from fuse object | ||
| int fts_k = 50; | ||
| int vec_k = 50; | ||
| int rrf_k0 = 60; | ||
| double w_fts = 1.0; | ||
| double w_vec = 1.0; | ||
|
|
||
| if (arguments.contains("fuse") && arguments["fuse"].is_object()) { | ||
| const json& fuse_params = arguments["fuse"]; | ||
| fts_k = validate_k(get_json_int(fuse_params, "fts_k", 50)); | ||
| vec_k = validate_k(get_json_int(fuse_params, "vec_k", 50)); | ||
| rrf_k0 = get_json_int(fuse_params, "rrf_k0", 60); | ||
| w_fts = get_json_int(fuse_params, "w_fts", 1.0); | ||
| w_vec = get_json_int(fuse_params, "w_vec", 1.0); | ||
| } else { | ||
| // Fallback to top-level parameters for backward compatibility | ||
| fts_k = validate_k(get_json_int(arguments, "fts_k", 50)); | ||
| vec_k = validate_k(get_json_int(arguments, "vec_k", 50)); | ||
| rrf_k0 = get_json_int(arguments, "rrf_k0", 60); | ||
| w_fts = get_json_int(arguments, "w_fts", 1.0); | ||
| w_vec = get_json_int(arguments, "w_vec", 1.0); | ||
| } |
There was a problem hiding this comment.
Type mismatch: using get_json_int for double weights truncates values.
w_fts and w_vec are declared as double but extracted using get_json_int, which returns int. This truncates fractional weights (e.g., 0.5 becomes 0, 1.7 becomes 1), breaking the intended RRF weighting functionality.
Suggested fix: Add get_json_double helper and use it
Add a new helper method:
double RAG_Tool_Handler::get_json_double(const json& j, const std::string& key, double default_val) {
if (j.contains(key) && !j[key].is_null()) {
if (j[key].is_number()) {
return j[key].get<double>();
} else if (j[key].is_string()) {
try {
return std::stod(j[key].get<std::string>());
} catch (const std::exception& e) {
proxy_error("RAG_Tool_Handler: Failed to convert string to double for key '%s': %s\n",
key.c_str(), e.what());
return default_val;
}
}
}
return default_val;
}Then fix the extraction:
if (arguments.contains("fuse") && arguments["fuse"].is_object()) {
const json& fuse_params = arguments["fuse"];
fts_k = validate_k(get_json_int(fuse_params, "fts_k", 50));
vec_k = validate_k(get_json_int(fuse_params, "vec_k", 50));
rrf_k0 = get_json_int(fuse_params, "rrf_k0", 60);
- w_fts = get_json_int(fuse_params, "w_fts", 1.0);
- w_vec = get_json_int(fuse_params, "w_vec", 1.0);
+ w_fts = get_json_double(fuse_params, "w_fts", 1.0);
+ w_vec = get_json_double(fuse_params, "w_vec", 1.0);
} else {
// Fallback to top-level parameters for backward compatibility
fts_k = validate_k(get_json_int(arguments, "fts_k", 50));
vec_k = validate_k(get_json_int(arguments, "vec_k", 50));
rrf_k0 = get_json_int(arguments, "rrf_k0", 60);
- w_fts = get_json_int(arguments, "w_fts", 1.0);
- w_vec = get_json_int(arguments, "w_vec", 1.0);
+ w_fts = get_json_double(arguments, "w_fts", 1.0);
+ w_vec = get_json_double(arguments, "w_vec", 1.0);
}🤖 Prompt for AI Agents
In `@lib/RAG_Tool_Handler.cpp` around lines 1401 - 1422, The w_fts and w_vec
doubles are being read with get_json_int (truncating fractional values); add a
helper RAG_Tool_Handler::get_json_double(const json&, const std::string&,
double) that safely extracts numbers/strings to double (with fallback to default
and error handling), then replace the two get_json_int calls for w_fts and w_vec
in both the fuse_params branch and the fallback branch with get_json_double,
leaving validate_k and rrf_k0 extraction unchanged.
| ## Status: COMPLETE | ||
|
|
||
| All required tasks for implementing the ProxySQL RAG (Retrieval-Augmented Generation) subsystem have been successfully completed according to the blueprint specifications. |
There was a problem hiding this comment.
Align completion wording with the PR’s WIP status.
This file says “Status: COMPLETE” and “ready for production use,” but the PR is marked WIP. Please soften to “WIP / pending integration testing” to avoid overstating readiness.
✏️ Suggested wording tweak
-## Status: COMPLETE
+## Status: WIP (pending integration testing)
@@
-The RAG subsystem is ready for production use. To enable:
+The RAG subsystem is ready for integration testing. To enable:Also applies to: 84-85
🤖 Prompt for AI Agents
In `@RAG_COMPLETION_SUMMARY.md` around lines 3 - 5, Update the summary wording in
RAG_COMPLETION_SUMMARY.md to reflect the PR's WIP state: replace the header
string "Status: COMPLETE" with "Status: WIP / pending integration testing" and
change any phrases that assert production readiness (e.g., "ready for production
use") to a softer phrasing such as "not yet ready for production; pending
integration testing"; apply these edits to the occurrences around the top block
and the repeated lines referenced (the other occurrence at lines 84-85).
| # -h, --help Show help | ||
| # | ||
|
|
||
| set -e |
There was a problem hiding this comment.
set -e prevents test summary on failure.
With set -e, when a test function returns non-zero (e.g., line 103), the script exits immediately without showing the summary (lines 198-210). Consider removing set -e or trapping errors to ensure the summary is always displayed.
Proposed fix
-set -e
+# Don't use set -e so we can show summary even on failuresOr use explicit exit in main:
main() {
log "Starting RAG functionality tests..."
log "MCP Host: ${MCP_HOST}:${MCP_PORT}"
log ""
# Run tests
- test_mcp_connectivity
- test_tool_discovery
- test_rag_tools
- test_rag_admin_stats
+ test_mcp_connectivity || true
+ test_tool_discovery || true
+ test_rag_tools || true
+ test_rag_admin_stats || true📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| set -e | |
| # Don't use set -e so we can show summary even on failures |
🤖 Prompt for AI Agents
In `@scripts/mcp/test_rag.sh` at line 14, Remove or neutralize the global `set -e`
so a single failing test doesn't abort before the test summary is printed;
alternatively replace it with an error trap that captures the exit code, runs
the test-summary routine, then exits with that code (e.g., trap 'rc=$?; <call
your summary function or the test-summary block>; exit $rc' ERR or use trap on
EXIT). Update the script to invoke the existing summary block (the test summary
code in this file) from the trap so it always runs on failure, or remove `set
-e` and ensure `main` or the test runner explicitly exits after calling the
summary.
| log_success() { | ||
| if [ "$QUIET" = false ]; then | ||
| echo -e "${GREEN}✓${NC} $@" | ||
| fi | ||
| } | ||
|
|
||
| log_failure() { | ||
| if [ "$QUIET" = false ]; then | ||
| echo -e "${RED}✗${NC} $@" | ||
| fi | ||
| } |
There was a problem hiding this comment.
Fix argument handling in log functions.
Using $@ after a string prefix causes shellcheck SC2145. Use $* instead for proper string concatenation.
Proposed fix
log_success() {
if [ "$QUIET" = false ]; then
- echo -e "${GREEN}✓${NC} $@"
+ echo -e "${GREEN}✓${NC} $*"
fi
}
log_failure() {
if [ "$QUIET" = false ]; then
- echo -e "${RED}✗${NC} $@"
+ echo -e "${RED}✗${NC} $*"
fi
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| log_success() { | |
| if [ "$QUIET" = false ]; then | |
| echo -e "${GREEN}✓${NC} $@" | |
| fi | |
| } | |
| log_failure() { | |
| if [ "$QUIET" = false ]; then | |
| echo -e "${RED}✗${NC} $@" | |
| fi | |
| } | |
| log_success() { | |
| if [ "$QUIET" = false ]; then | |
| echo -e "${GREEN}✓${NC} $*" | |
| fi | |
| } | |
| log_failure() { | |
| if [ "$QUIET" = false ]; then | |
| echo -e "${RED}✗${NC} $*" | |
| fi | |
| } |
🧰 Tools
🪛 Shellcheck (0.11.0)
[error] 52-52: Argument mixes string and array. Use * or separate argument.
(SC2145)
[error] 58-58: Argument mixes string and array. Use * or separate argument.
(SC2145)
🤖 Prompt for AI Agents
In `@scripts/mcp/test_rag.sh` around lines 50 - 60, The log_success and
log_failure functions currently use $@ after a string prefix which triggers
shellcheck SC2145; update both functions to concatenate all arguments as a
single string by replacing $@ with "$*" in the echo lines inside log_success and
log_failure (keep the QUIET check and existing color prefixes intact).
test/build_rag_test.sh
Outdated
| # Compile the test | ||
| echo "Compiling test_rag_schema..." | ||
| g++ -std=c++11 -ggdb ${IDIRS} test_rag_schema.cpp -o test_rag_schema -pthread -ldl | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if test_rag_schema.cpp uses SQLite3DB
echo "=== Checking test_rag_schema.cpp for SQLite3DB usage ==="
fd -a "test_rag_schema.cpp" -x grep -n "SQLite3DB" {}
# Check for SQLite3DB class declaration
echo -e "\n=== Looking for SQLite3DB class declaration ==="
fd -a "sqlite3db.h" -x cat {}
# Find SQLite3DB implementation
echo -e "\n=== Checking for SQLite3DB implementation files ==="
fd -a "sqlite3db.cpp"
# Show the actual compile line in the test script
echo -e "\n=== Showing lines 46-49 from test/build_rag_test.sh ==="
sed -n '46,49p' test/build_rag_test.shRepository: ProxySQL/proxysql-vec
Length of output: 8841
🏁 Script executed:
#!/bin/bash
# Check the build script more completely
echo "=== Full test/build_rag_test.sh content ==="
cat test/build_rag_test.sh
echo -e "\n=== Check if there's a Makefile ==="
find . -maxdepth 2 -name "Makefile" -o -name "makefile"
echo -e "\n=== Check if sqlite3db is linked elsewhere ==="
grep -r "sqlite3db" test/ --include="*.sh" --include="*.mk" 2>/dev/null || echo "No sqlite3db found in test scripts"Repository: ProxySQL/proxysql-vec
Length of output: 2211
🏁 Script executed:
#!/bin/bash
# Check test/Makefile
echo "=== test/Makefile content ==="
cat test/Makefile
echo -e "\n=== Check test_rag_schema.cpp includes and structure ==="
head -50 test/test_rag_schema.cpp
echo -e "\n=== Full includes and dependencies of test_rag_schema.cpp ==="
rg -n "#include|#pragma" test/test_rag_schema.cppRepository: ProxySQL/proxysql-vec
Length of output: 2649
Compile line is missing SQLite3DB/link objects.
test_rag_schema.cpp uses SQLite3DB, which is implemented in lib/sqlite3db.cpp and needs to be linked (plus sqlite3). As written, this will fail at link time with undefined reference errors. Either link the required objects or use the Makefile target instead.
🛠️ Example fix (link required objects)
-g++ -std=c++11 -ggdb ${IDIRS} test_rag_schema.cpp -o test_rag_schema -pthread -ldl
+g++ -std=c++11 -ggdb ${IDIRS} \
+ lib/sqlite3db.cpp \
+ deps/sqlite3/sqlite3/sqlite3.o \
+ test_rag_schema.cpp -o test_rag_schema -pthread -ldl📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # Compile the test | |
| echo "Compiling test_rag_schema..." | |
| g++ -std=c++11 -ggdb ${IDIRS} test_rag_schema.cpp -o test_rag_schema -pthread -ldl | |
| # Compile the test | |
| echo "Compiling test_rag_schema..." | |
| g++ -std=c++11 -ggdb ${IDIRS} \ | |
| lib/sqlite3db.cpp \ | |
| deps/sqlite3/sqlite3/sqlite3.o \ | |
| test_rag_schema.cpp -o test_rag_schema -pthread -ldl | |
🤖 Prompt for AI Agents
In `@test/build_rag_test.sh` around lines 46 - 49, The compile command for
test_rag_schema.cpp omits the SQLite3DB implementation and sqlite3 library,
causing undefined references; update the build step that invokes g++ for
test_rag_schema to also link the SQLite3DB object/compiled file (e.g.,
lib/sqlite3db.cpp compiled to sqlite3db.o or the corresponding object) and the
sqlite3 library (e.g., -lsqlite3), or call the existing Makefile target that
already builds and links SQLite3DB; ensure references to SQLite3DB and sqlite3
are included in the g++ link line so test_rag_schema links successfully.
test/Makefile
Outdated
| test_rag_schema: test_rag_schema.cpp | ||
| $(CXX) -ggdb $(PROXYSQL_OBJS) test_rag_schema.cpp -o test_rag_schema $(IDIRS) $(LDIRS) $(PROXYSQL_LIBS) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find files that define PROXYSQL_OBJS
find . -type f \( -name "*.mk" -o -name "Makefile" \) | head -20Repository: ProxySQL/proxysql-vec
Length of output: 571
🏁 Script executed:
#!/bin/bash
# Search for PROXYSQL_OBJS definition
rg -n "PROXYSQL_OBJS" --type makefileRepository: ProxySQL/proxysql-vec
Length of output: 97
🏁 Script executed:
#!/bin/bash
# Check what's in the test/Makefile around the test_rag_schema target
cat -n test/Makefile | sed -n '25,40p'Repository: ProxySQL/proxysql-vec
Length of output: 512
🏁 Script executed:
#!/bin/bash
# Search for PROXYSQL_OBJS definition without type restriction
rg -n "PROXYSQL_OBJS" .Repository: ProxySQL/proxysql-vec
Length of output: 188
🏁 Script executed:
#!/bin/bash
# Check makefiles_vars.mk for PROXYSQL_OBJS definition
cat include/makefiles_vars.mk | head -100Repository: ProxySQL/proxysql-vec
Length of output: 1632
🏁 Script executed:
#!/bin/bash
# Get full content of makefiles_vars.mk to find PROXYSQL_OBJS
wc -l include/makefiles_vars.mk
cat include/makefiles_vars.mk | grep -n "PROXYSQL_OBJS"Repository: ProxySQL/proxysql-vec
Length of output: 93
🏁 Script executed:
#!/bin/bash
# Check makefiles_paths.mk
cat include/makefiles_paths.mk | grep -n "PROXYSQL_OBJS"Repository: ProxySQL/proxysql-vec
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Check main Makefile
cat Makefile | grep -n "PROXYSQL_OBJS"Repository: ProxySQL/proxysql-vec
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Read entire test/Makefile to find PROXYSQL_OBJS definition
cat test/MakefileRepository: ProxySQL/proxysql-vec
Length of output: 1025
🏁 Script executed:
#!/bin/bash
# Read entire makefiles_vars.mk
cat include/makefiles_vars.mkRepository: ProxySQL/proxysql-vec
Length of output: 1632
🏁 Script executed:
#!/bin/bash
# Read entire makefiles_paths.mk
cat include/makefiles_paths.mkRepository: ProxySQL/proxysql-vec
Length of output: 4244
🏁 Script executed:
#!/bin/bash
# Search for any variable with "OBJS" in its name across makefiles
rg -n "OBJS\s*:=" include/Repository: ProxySQL/proxysql-vec
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Search for OBJS in all makefiles
rg -n "OBJS" --type-add 'mk:*.mk' -t mkRepository: ProxySQL/proxysql-vec
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Check if PROXYSQL_OBJS is defined in lib/Makefile or src/Makefile
grep -n "PROXYSQL_OBJS\|^OBJS" lib/Makefile src/Makefile 2>/dev/null | head -30Repository: ProxySQL/proxysql-vec
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Broad search for PROXYSQL_OBJS across entire repository
rg "PROXYSQL_OBJS" .Repository: ProxySQL/proxysql-vec
Length of output: 185
🏁 Script executed:
#!/bin/bash
# Also search for any file that might define object lists
rg -n "\.o|OBJS|OBJECTS" src/Makefile lib/Makefile 2>/dev/null | head -50Repository: ProxySQL/proxysql-vec
Length of output: 3448
🏁 Script executed:
#!/bin/bash
# Find and check test_rag_schema.cpp
find . -name "test_rag_schema.cpp" -type fRepository: ProxySQL/proxysql-vec
Length of output: 91
🏁 Script executed:
#!/bin/bash
# Check if test_rag_schema.cpp exists and read it
if [ -f test/test_rag_schema.cpp ]; then
wc -l test/test_rag_schema.cpp
head -50 test/test_rag_schema.cpp
fiRepository: ProxySQL/proxysql-vec
Length of output: 1477
Replace undefined $(PROXYSQL_OBJS) with explicit library dependencies.
The variable $(PROXYSQL_OBJS) is undefined in this codebase, so the target will fail to link. Since test_rag_schema.cpp includes sqlite3db.h, it needs the corresponding object files linked. Follow the pattern of the sqlite_history_convert target on line 28–29.
Example fix
test_rag_schema: test_rag_schema.cpp
- $(CXX) -ggdb $(PROXYSQL_OBJS) test_rag_schema.cpp -o test_rag_schema $(IDIRS) $(LDIRS) $(PROXYSQL_LIBS)
+ $(CXX) -ggdb ../lib/sqlite3db.cpp ../deps/sqlite3/sqlite3/sqlite3.o test_rag_schema.cpp -o test_rag_schema $(IDIRS) -pthread -ldl🤖 Prompt for AI Agents
In `@test/Makefile` around lines 31 - 32, The test_rag_schema Makefile target
references an undefined variable $(PROXYSQL_OBJS); replace it with the explicit
object/library dependencies used elsewhere (follow the sqlite_history_convert
target pattern) so test_rag_schema links the sqlite-related objects required by
test_rag_schema.cpp (e.g., the sqlite3db-related object files and any other
PROXYSQL libraries already listed via $(PROXYSQL_LIBS)/IDIRS/LDIRS). Update the
test_rag_schema rule to remove $(PROXYSQL_OBJS) and list the same object
files/libraries referenced by sqlite_history_convert so the linker can find the
sqlite3db symbols.
test/test_rag_schema.cpp
Outdated
| // Open the default vector database path | ||
| const char* db_path = "/var/lib/proxysql/ai_features.db"; | ||
| std::cout << "Testing RAG schema in database: " << db_path << std::endl; |
There was a problem hiding this comment.
Avoid hard-coded DB path to reduce test flakiness.
ProxySQL datadir can vary; allow an env override with a default fallback.
🧩 Suggested change
@@
-#include <string>
+#include <string>
+#include <cstdlib>
@@
- const char* db_path = "/var/lib/proxysql/ai_features.db";
+ const char* db_path = std::getenv("PROXYSQL_AI_FEATURES_DB");
+ if (!db_path) {
+ db_path = "/var/lib/proxysql/ai_features.db";
+ }🤖 Prompt for AI Agents
In `@test/test_rag_schema.cpp` around lines 32 - 34, Replace the hard-coded
db_path constant in test/test_rag_schema.cpp with an environment-variable-driven
value: read an env var (e.g., PROXYSQL_DATADIR or PROXYSQL_AI_DB) via getenv and
use that if present, otherwise fall back to the current default
"/var/lib/proxysql/ai_features.db"; update the code that prints and uses db_path
(the db_path variable and the std::cout line) so tests can be configured by CI
or local environments without changing source.
- Remove Doxyfile that was added by mistake - Remove .doxygen files from doc/ directory that were generated by mistake - Clean up documentation artifacts that shouldn't have been committed
- Address SQL injection vulnerabilities by adding input validation and escaping - Fix configuration variable handling in get_variable and set_variable methods for RAG variables - Make embedding dimension configurable for rag_vec_chunks table - Remove code duplication in SQL filter building logic by creating consolidated build_sql_filters function - Update all search tools (FTS, vector, hybrid) to use consolidated filter building
- Move RAG test files to dedicated test/rag/ directory - Create proper Makefile in test/rag/ directory - Remove build_rag_test.sh script (replaced by Makefile) - Revert changes to main test/Makefile - Update documentation to reflect new test structure
- Move RAG test files to dedicated test/rag/ directory - Create proper Makefile in test/rag/ directory - Remove build_rag_test.sh script (replaced by Makefile) - Update .gitignore to exclude test/rag/test_rag_schema executable - Update documentation to reflect new test structure
|
I've addressed all the legitimate concerns raised by the AI agents in the code review:
All changes have been pushed to the |
…ove MAIN_PROXY_SQLITE3 from main.cpp
…ents (address code-review)
Use proxy_sqlite3_* wrappers and canonical proxy symbol TU
Summary
This PR completes the implementation of the ProxySQL RAG (Retrieval-Augmented Generation) subsystem and adds comprehensive Doxygen documentation.
Features Implemented
Complete RAG Tool Handler with all MCP tools:
rag.search_fts: Keyword search using FTS5rag.search_vector: Semantic search using vector embeddingsrag.search_hybrid: Hybrid search with two modes (fuse and fts_then_vec)rag.get_chunks: Fetch chunk content by chunk_idrag.get_docs: Fetch document content by doc_idrag.fetch_from_source: Refetch authoritative data from sourcerag.admin.stats: Operational statisticsDatabase integration with complete RAG schema:
rag_sources: Ingestion configurationrag_documents: Canonical documentsrag_chunks: Chunked contentrag_fts_chunks: FTS5 indexrag_vec_chunks: Vector indexrag_sync_state: Sync state trackingrag_chunk_view: Debugging viewComprehensive filtering capabilities:
Security features:
Documentation
Testing
The RAG subsystem is ready for integration testing and can be extended with additional features in future versions.