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}