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_response_envelope;
17pub mod audit_record_builder;
18pub mod batch_client;
19pub mod citation_parser;
20pub mod cost_guard;
21pub mod dedup_cache;
22pub mod determinism_decider;
23pub mod explain_plan_builder;
24pub mod grpc_ask_message;
25pub mod local_embedding;
26pub mod mcp_ask_tool;
27pub mod metrics;
28pub mod ner;
29pub mod pg_wire_ask_row_encoder;
30pub mod prompt_assembler;
31pub mod prompt_template;
32pub mod provider_capabilities;
33pub mod provider_failover;
34pub mod rrf_fuser;
35pub mod sources_fingerprint;
36pub mod sse_frame_encoder;
37pub mod strict_validator;
38pub mod text_chunker;
39pub mod transport;
40pub mod urn_codec;
41
42pub(crate) fn block_on_ai<F, T>(future: F) -> crate::RedDBResult<T>
43where
44    F: std::future::Future<Output = T> + Send + 'static,
45    T: Send + 'static,
46{
47    if let Ok(handle) = tokio::runtime::Handle::try_current() {
48        if matches!(
49            handle.runtime_flavor(),
50            tokio::runtime::RuntimeFlavor::MultiThread
51        ) {
52            return Ok(tokio::task::block_in_place(|| handle.block_on(future)));
53        }
54
55        return std::thread::Builder::new()
56            .name("reddb-ai-blocking".to_string())
57            .spawn(move || {
58                let runtime = tokio::runtime::Builder::new_current_thread()
59                    .enable_all()
60                    .build()
61                    .map_err(|err| {
62                        crate::RedDBError::Query(format!("failed to start AI runtime: {err}"))
63                    })?;
64                Ok(runtime.block_on(future))
65            })
66            .map_err(|err| {
67                crate::RedDBError::Query(format!("failed to spawn AI runtime thread: {err}"))
68            })?
69            .join()
70            .map_err(|_| crate::RedDBError::Query("AI runtime thread panicked".to_string()))?;
71    }
72
73    let runtime = tokio::runtime::Builder::new_current_thread()
74        .enable_all()
75        .build()
76        .map_err(|err| crate::RedDBError::Query(format!("failed to start AI runtime: {err}")))?;
77    Ok(runtime.block_on(future))
78}