Skip to main content

rosetta_aisp_llm/
lib.rs

1//! Rosetta AISP LLM Fallback
2//!
3//! Provides LLM-powered fallback for AISP conversion when deterministic
4//! Rosetta mappings have low confidence. Uses Claude SDK for intelligent
5//! prose-to-symbol translation.
6//!
7//! # Example
8//!
9//! ```no_run
10//! use rosetta_aisp_llm::{convert_with_fallback, ConversionOptionsExt};
11//!
12//! # async fn example() {
13//! let prose = "Define a type User with valid credentials";
14//! let result = convert_with_fallback(prose, None).await;
15//! println!("Output: {}", result.output);
16//! println!("Used LLM: {}", result.used_fallback);
17//! # }
18//! ```
19
20mod claude;
21mod provider;
22
23pub use claude::ClaudeFallback;
24pub use provider::{LlmProvider, LlmResult};
25
26// Re-export rosetta-aisp types for convenience
27pub use rosetta_aisp::{
28    AispConverter, ConversionOptions, ConversionResult, ConversionTier, RosettaStone, TokenStats,
29};
30
31/// Extended conversion options with LLM fallback support
32#[derive(Debug, Clone)]
33pub struct ConversionOptionsExt {
34    /// Force specific tier (auto-detect if None)
35    pub tier: Option<ConversionTier>,
36    /// Confidence threshold for LLM fallback (default: 0.8)
37    pub confidence_threshold: Option<f64>,
38    /// Enable LLM fallback
39    pub enable_llm_fallback: bool,
40    /// LLM model to use (default: haiku)
41    pub llm_model: Option<String>,
42    /// Use AISP symbolic prompt instead of English prompt (default: true)
43    pub use_aisp_prompt: bool,
44}
45
46impl Default for ConversionOptionsExt {
47    fn default() -> Self {
48        Self {
49            tier: None,
50            confidence_threshold: None,
51            enable_llm_fallback: false,
52            llm_model: None,
53            use_aisp_prompt: true, // AISP prompt is default for accuracy
54        }
55    }
56}
57
58/// Convert prose to AISP with optional LLM fallback
59///
60/// This function first attempts deterministic conversion using rosetta-aisp.
61/// If the confidence is below the threshold and LLM fallback is enabled,
62/// it uses Claude to improve the conversion.
63///
64/// # Arguments
65///
66/// * `prose` - The natural language text to convert
67/// * `options` - Optional configuration for conversion behavior
68///
69/// # Returns
70///
71/// A `ConversionResult` containing the AISP output and metadata
72pub async fn convert_with_fallback(
73    prose: &str,
74    options: Option<ConversionOptionsExt>,
75) -> ConversionResult {
76    let opts = options.unwrap_or_default();
77
78    // Convert using rosetta-aisp's ConversionOptions
79    let base_options = ConversionOptions {
80        tier: opts.tier,
81        confidence_threshold: opts.confidence_threshold,
82    };
83
84    let result = AispConverter::convert(prose, Some(base_options));
85    let threshold = opts.confidence_threshold.unwrap_or(0.8);
86
87    // Check if LLM fallback is needed
88    if opts.enable_llm_fallback && result.confidence < threshold {
89        let provider = if let Some(model) = &opts.llm_model {
90            ClaudeFallback::with_model(model)
91        } else {
92            ClaudeFallback::new()
93        };
94
95        if provider.is_available().await {
96            if let Ok(llm_result) = provider
97                .convert(
98                    prose,
99                    result.tier,
100                    &result.unmapped,
101                    Some(&result.output),
102                    opts.use_aisp_prompt,
103                )
104                .await
105            {
106                return llm_result.to_conversion_result(result.tier, prose.len());
107            }
108        }
109    }
110
111    result
112}