use crate::groq_client::{GroqClient, models};
#[allow(async_fn_in_trait)]
pub trait UnwrapOrAi<T> {
async fn unwrap_or_ai_impl(self, prompt: String) -> T;
}
impl<T, E> UnwrapOrAi<T> for Result<T, E>
where
T: serde::de::DeserializeOwned + schemars::JsonSchema + Unpin + Clone + Send + Sync + 'static,
{
async fn unwrap_or_ai_impl(self, prompt: String) -> T {
match self {
Ok(val) => val,
Err(_) => {
println!("Result error detected, calling AI for recovery...");
match call_ai_for_type::<T>(prompt).await {
Ok(ai_result) => ai_result,
Err(ai_error) => {
panic!("AI recovery failed: {}", ai_error);
}
}
}
}
}
}
impl<T> UnwrapOrAi<T> for Option<T>
where
T: serde::de::DeserializeOwned + schemars::JsonSchema + Unpin + Clone + Send + Sync + 'static,
{
async fn unwrap_or_ai_impl(self, prompt: String) -> T {
match self {
Some(val) => val,
None => {
println!("Option is None, calling AI for recovery...");
match call_ai_for_type::<T>(prompt).await {
Ok(ai_result) => {
println!("AI recovery successful!");
ai_result
}
Err(ai_error) => {
panic!("AI recovery failed: {}", ai_error);
}
}
}
}
}
}
pub async fn call_ai_for_type<T>(prompt: String) -> Result<T, Box<dyn std::error::Error>>
where
T: serde::de::DeserializeOwned + schemars::JsonSchema + Unpin + Clone + Send + Sync + 'static,
{
let api_key = std::env::var("GROQ_API").map_err(|_| "GROQ_API environment variable not set")?;
let groq = GroqClient::new(api_key);
let ai_response: T = groq.chat_completion_typed(
models::KIMI_K2, vec![
("system", "You are an AI error recovery assistant. When given an error message and program context, your task is to infer the most likely intended response or output. Do not explain the error—directly provide the corrected or plausible output as if the error had not occurred."),
("user", &prompt)
]
).await?;
Ok(ai_response)
}
#[macro_export]
macro_rules! unwrap_or_ai {
($fn_name:ident($($args:expr),*)) => {{
use $crate::unwrap_or_ai::UnwrapOrAi;
use $crate::paste;
async {
let result = $fn_name($($args),*);
let source_code = paste::paste! { [<print_source_of_ $fn_name>]() };
let prompt = format!(
"The following function call failed: {}({})
Function name: {}
Parameters: {:?}
Source code: {}
This function should return the appropriate type. Generate a reasonable response as valid JSON.",
stringify!($fn_name),
stringify!($($args),*),
stringify!($fn_name),
stringify!($($args),*),
source_code
);
result.unwrap_or_ai_impl(prompt).await
}
}};
($fn_call:expr) => {{
use $crate::unwrap_or_ai::UnwrapOrAi;
async {
let result = $fn_call;
let prompt = format!(
"The following function call failed: {}
Generate a reasonable response as valid JSON that matches the expected return type.",
stringify!($fn_call)
);
println!("Prompt for AI: {}", prompt);
result.unwrap_or_ai_impl(prompt).await
}
}};
}