terraphim_grep 1.20.0

Intelligent hybrid grep with RLM fallback and KG curation
Documentation
#[cfg(feature = "llm")]
use crate::signatures::{ConceptExtractionSignature, RlmSignature};
#[cfg(feature = "llm")]
use std::sync::Arc;
#[cfg(feature = "llm")]
use terraphim_service::llm::LlmClient;

use crate::error::Result;
use crate::signatures::NewConcept;

#[cfg(feature = "llm")]
pub struct KgCurationRlm {
    llm_client: Arc<dyn LlmClient>,
}

#[cfg(feature = "llm")]
impl KgCurationRlm {
    pub fn new(llm_client: Arc<dyn LlmClient>) -> Self {
        Self { llm_client }
    }

    pub async fn extract_and_index(
        &self,
        query: &str,
        rlm_answer: &str,
    ) -> Result<Vec<NewConcept>> {
        use crate::error::TerraphimGrepError;

        let prompt = format!(
            "Extract new concepts from this interaction:\n\n\
            Query: {}\n\
            Answer: {}\n\n\
            {}\n\n\
            Output JSON only.",
            query,
            rlm_answer,
            ConceptExtractionSignature {}.instructions()
        );

        let messages = vec![serde_json::json!({
            "role": "user",
            "content": prompt
        })];

        let response = self
            .llm_client
            .chat_completion(
                messages,
                terraphim_service::llm::ChatOptions {
                    max_tokens: Some(1000),
                    temperature: Some(0.3),
                },
            )
            .await
            .map_err(|e| TerraphimGrepError::RlmFailed(e.to_string()))?;

        let signature = ConceptExtractionSignature {};
        let concepts = signature.parse(&response)?;

        Ok(concepts)
    }
}

#[cfg(not(feature = "llm"))]
pub struct KgCurationRlm;

#[cfg(not(feature = "llm"))]
impl Default for KgCurationRlm {
    fn default() -> Self {
        Self
    }
}

#[cfg(not(feature = "llm"))]
impl KgCurationRlm {
    pub fn new() -> Self {
        Self
    }

    pub async fn extract_and_index(
        &self,
        _query: &str,
        _rlm_answer: &str,
    ) -> Result<Vec<NewConcept>> {
        use crate::error::TerraphimGrepError;
        Err(TerraphimGrepError::LlmNotConfigured(
            "LLM feature not enabled".to_string(),
        ))
    }
}

#[cfg(test)]
mod tests {
    #[cfg(not(feature = "llm"))]
    use super::*;

    #[cfg(not(feature = "llm"))]
    #[test]
    fn test_kg_curation_new() {
        let _curation = KgCurationRlm::new();
    }
}