MCPcopy Create free account
hub / github.com/RunanywhereAI/RCLI / rcli_rag_query

Function rcli_rag_query

src/api/rcli_api.cpp:2551–2637  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

2549}
2550
2551const char* rcli_rag_query(RCLIHandle handle, const char* query) {
2552 if (!handle || !query) return "";
2553 auto* engine = static_cast<RCLIEngine*>(handle);
2554 if (!engine->rag_ready || !engine->rag_retriever || !engine->rag_embedding) {
2555 return "{\"error\": \"RAG not initialized. Run rcli_rag_ingest() first.\"}";
2556 }
2557
2558 std::lock_guard<std::mutex> lock(engine->mutex);
2559
2560 auto query_embedding = engine->rag_embedding->embed(std::string(query));
2561 if (query_embedding.empty()) {
2562 return "{\"error\": \"Failed to embed query\"}";
2563 }
2564
2565 auto results = engine->rag_retriever->retrieve(
2566 std::string(query), query_embedding, 5);
2567
2568 if (results.empty()) {
2569 engine->last_rag_result = "{\"results\": [], \"answer\": \"No relevant documents found.\"}";
2570 return engine->last_rag_result.c_str();
2571 }
2572
2573 // Build context from retrieved chunks
2574 std::string context;
2575 for (size_t i = 0; i < results.size(); i++) {
2576 context += "[" + std::to_string(i + 1) + "] " + std::string(results[i].text) + "\n\n";
2577 }
2578
2579 // Generate answer using LLM with retrieved context.
2580 // The system prompt enforces speech-friendly output since responses are
2581 // streamed to TTS — no bullets, numbered lists, markdown, or citations.
2582 std::string rag_system = rastack::apply_personality(
2583 "You are RCLI, a voice assistant that answers questions using provided documents. "
2584 "Your response will be spoken aloud by a text-to-speech engine, so you MUST follow these rules:\n"
2585 "- Answer in plain, natural conversational sentences only.\n"
2586 "- NEVER use bullet points, numbered lists, markdown, or any formatting.\n"
2587 "- NEVER include citations like [1], [2], or source references.\n"
2588 "- NEVER use parentheses for asides or abbreviations.\n"
2589 "- Do NOT use <think> tags or internal reasoning.\n"
2590 "- Keep your answer concise — 2 to 4 sentences maximum.\n"
2591 "- If the answer is not in the context, say so briefly.",
2592 engine->personality_key);
2593
2594 std::string rag_prompt =
2595 "Context:\n" + context + "\n"
2596 "Question: " + std::string(query);
2597
2598 std::string answer;
2599 if (engine->pipeline.using_metalrt()) {
2600 auto& mrt = engine->pipeline.metalrt_llm();
2601 std::string rag_full = mrt.profile().build_chat_prompt(rag_system, {}, rag_prompt);
2602 answer = mrt.generate_raw(rag_full, nullptr);
2603 engine->metalrt_kv_continuation_len = 0;
2604 } else if (engine->pipeline.llm().is_initialized()) {
2605 answer = engine->pipeline.llm().generate(
2606 engine->pipeline.llm().build_chat_prompt(rag_system, {}, rag_prompt),
2607 nullptr);
2608 } else {

Callers 4

cmd_askFunction · 0.85
cmd_ragFunction · 0.85
stop_recordingMethod · 0.85
process_inputMethod · 0.85

Calls 12

apply_personalityFunction · 0.85
clean_llm_outputFunction · 0.85
embedMethod · 0.80
emptyMethod · 0.80
retrieveMethod · 0.80
using_metalrtMethod · 0.80
generate_rawMethod · 0.80
recache_system_promptMethod · 0.80
sizeMethod · 0.45
build_chat_promptMethod · 0.45
is_initializedMethod · 0.45
generateMethod · 0.45

Tested by

no test coverage detected