use super::plugin::{PromptTemplatePlugin, RhaiScriptPromptPlugin};
use mofa_plugins::hot_reload::{
HotReloadManager,
ReloadEvent,
};
use std::path::Path;
use std::sync::Arc;
use tokio::sync::RwLock;
use tracing::{info, warn};
pub struct HotReloadableRhaiPromptPlugin {
inner: Arc<RwLock<RhaiScriptPromptPlugin>>,
hot_reload_manager: Arc<RwLock<HotReloadManager>>,
}
impl HotReloadableRhaiPromptPlugin {
pub async fn new(script_path: impl AsRef<Path>) -> Self {
let script_path = script_path.as_ref().to_path_buf();
let inner = Arc::new(RwLock::new(RhaiScriptPromptPlugin::new(&script_path)));
let plugin_reload_config = mofa_plugins::hot_reload::HotReloadConfig::default();
let hot_reload_manager = HotReloadManager::new(plugin_reload_config);
{
}
Self {
inner,
hot_reload_manager: Arc::new(RwLock::new(hot_reload_manager)),
}
}
pub async fn start_reload_watcher(&self) {
let script_path = {
let inner_guard = self.inner.read().await;
inner_guard.script_path().to_path_buf()
};
let inner_clone = self.inner.clone();
{
let manager_guard = self.hot_reload_manager.write().await;
if let Err(e) = manager_guard.add_watch_path(&script_path).await {
warn!("Failed to add watch path: {}", e);
return;
}
}
{
let mut manager_guard = self.hot_reload_manager.write().await;
if let Err(e) = manager_guard.start().await {
warn!("Failed to start hot-reload manager: {}", e);
return;
}
}
info!(
"Hot-reload prompt template watcher started for path: {:?}",
script_path
);
let mut event_subscriber = self.hot_reload_manager.read().await.subscribe();
tokio::spawn(async move {
while let Ok(event) = event_subscriber.recv().await {
match event {
ReloadEvent::ReloadCompleted {
plugin_id,
path,
duration,
.. } => {
info!(
"Plugin {} reloaded in {:?} from path {:?}",
plugin_id, duration, path
);
let inner_guard = inner_clone.write().await;
if let Err(e) = inner_guard.refresh_templates().await {
warn!("Failed to refresh templates: {}", e);
}
}
ReloadEvent::ReloadFailed {
plugin_id,
path,
error,
attempt,
} => {
warn!(
"Plugin {} reload failed (attempt {}): {} at path {:?}",
plugin_id, attempt, error, path
);
}
ReloadEvent::PluginDiscovered { path } => {
info!("New plugin discovered at path {:?}", path);
let inner_guard = inner_clone.write().await;
if let Err(e) = inner_guard.refresh_templates().await {
warn!("Failed to refresh templates: {}", e);
}
}
ReloadEvent::PluginRemoved {
plugin_id,
path,
} => {
info!(
"Plugin {} removed from path {:?}",
plugin_id, path
);
let inner_guard = inner_clone.write().await;
if let Err(e) = inner_guard.refresh_templates().await {
warn!("Failed to refresh templates: {}", e);
}
}
_ => {} }
}
});
}
pub async fn stop_reload_watcher(&self) {
let mut manager_guard = self.hot_reload_manager.write().await;
if let Err(e) = manager_guard.stop().await {
warn!("Failed to stop hot-reload manager: {}", e);
}
}
pub async fn inner(&self) -> Arc<RwLock<RhaiScriptPromptPlugin>> {
self.inner.clone()
}
pub async fn set_active_scenario(&self, scenario: impl Into<String>) {
let scenario = scenario.into();
info!("Switching to scenario: {}", scenario);
let inner_guard = self.inner.write().await;
inner_guard.set_active_scenario(scenario).await;
}
}
#[async_trait::async_trait]
impl super::plugin::PromptTemplatePlugin for HotReloadableRhaiPromptPlugin {
async fn get_prompt_template(
&self,
scenario: &str,
) -> Option<Arc<super::template::PromptTemplate>> {
let inner_guard = self.inner.read().await;
inner_guard.get_prompt_template(scenario).await
}
async fn get_active_scenario(&self) -> String {
let inner_guard = self.inner.read().await;
inner_guard.get_active_scenario().await
}
async fn set_active_scenario(&self, scenario: &str) {
let inner_guard = self.inner.write().await;
inner_guard.set_active_scenario(scenario).await;
}
async fn get_available_scenarios(&self) -> Vec<String> {
let inner_guard = self.inner.read().await;
inner_guard.get_available_scenarios().await
}
async fn refresh_templates(&self) -> mofa_kernel::plugin::PluginResult<()> {
let inner_guard = self.inner.write().await;
inner_guard.refresh_templates().await
}
}