Skip to main content

reddb_server/runtime/ai/
mod.rs

1//! AI runtime modules.
2//!
3//! Houses the LLM-touching pieces of the AskPipeline:
4//!
5//! - [`prompt_template`] — typed-slot prompt assembly with secret
6//!   redaction and injection defence (issue #122).
7//! - [`ner`] — opt-in LLM backend for AskPipeline Stage 1 entity
8//!   extraction with auth gate, response sanitization, and a
9//!   configurable heuristic fallback (issue #123).
10//!
11//! Both modules are pure additions — call-site wiring lives in
12//! [`super::ask_pipeline`] and is opt-in via `ai.ner.backend = "llm"`
13//! at runtime config time.
14
15pub mod answer_cache_key;
16pub mod ask_planner;
17pub mod ask_response_envelope;
18pub mod ask_rql_planner;
19pub mod audit_record_builder;
20pub mod batch_client;
21pub mod cdc_enrichment;
22pub mod citation_parser;
23pub mod cost_guard;
24pub mod dedup_cache;
25pub mod determinism_decider;
26pub mod explain_plan_builder;
27pub mod grpc_ask_message;
28pub mod local_embedding;
29pub mod mcp_ask_tool;
30pub mod metrics;
31pub mod moderation;
32pub mod ner;
33pub mod pg_wire_ask_row_encoder;
34pub mod prompt_assembler;
35pub mod prompt_template;
36pub mod provider_capabilities;
37pub mod provider_failover;
38pub mod provider_gate;
39pub mod rrf_fuser;
40pub mod sources_fingerprint;
41pub mod sse_frame_encoder;
42pub mod strict_validator;
43pub mod text_chunker;
44pub mod transport;
45pub mod urn_codec;
46pub mod vision;
47
48pub(crate) fn block_on_ai<F, T>(future: F) -> crate::RedDBResult<T>
49where
50    F: std::future::Future<Output = T> + Send + 'static,
51    T: Send + 'static,
52{
53    if let Ok(handle) = tokio::runtime::Handle::try_current() {
54        if matches!(
55            handle.runtime_flavor(),
56            tokio::runtime::RuntimeFlavor::MultiThread
57        ) {
58            return Ok(tokio::task::block_in_place(|| handle.block_on(future)));
59        }
60
61        return std::thread::Builder::new()
62            .name("reddb-ai-blocking".to_string())
63            .spawn(move || {
64                let runtime = tokio::runtime::Builder::new_current_thread()
65                    .enable_all()
66                    .build()
67                    .map_err(|err| {
68                        crate::RedDBError::Query(format!("failed to start AI runtime: {err}"))
69                    })?;
70                Ok(runtime.block_on(future))
71            })
72            .map_err(|err| {
73                crate::RedDBError::Query(format!("failed to spawn AI runtime thread: {err}"))
74            })?
75            .join()
76            .map_err(|_| crate::RedDBError::Query("AI runtime thread panicked".to_string()))?;
77    }
78
79    let runtime = tokio::runtime::Builder::new_current_thread()
80        .enable_all()
81        .build()
82        .map_err(|err| crate::RedDBError::Query(format!("failed to start AI runtime: {err}")))?;
83    Ok(runtime.block_on(future))
84}