agent-diva-manager 0.4.9

Manager server for Agent Diva
Documentation
use agent_diva_providers::{
    CustomProviderUpsert, ProviderCatalogService, ProviderModelCatalogView, ProviderView,
};
use tokio::sync::oneshot;

use super::Manager;

impl Manager {
    pub(super) fn handle_get_providers(&self, reply: oneshot::Sender<Vec<ProviderView>>) {
        let config = self.loader.load().unwrap_or_default();
        let providers = ProviderCatalogService::new().list_provider_views(&config);
        let _ = reply.send(providers);
    }

    pub(super) fn handle_get_provider(
        &self,
        name: String,
        reply: oneshot::Sender<Result<Option<ProviderView>, String>>,
    ) {
        let config = self.loader.load().unwrap_or_default();
        let provider = ProviderCatalogService::new().get_provider_view(&config, &name);
        let _ = reply.send(Ok(provider));
    }

    pub(super) async fn handle_get_provider_models(
        &self,
        name: String,
        runtime: bool,
        reply: oneshot::Sender<ProviderModelCatalogView>,
    ) {
        let config = self.loader.load().unwrap_or_default();
        let fallback = ProviderModelCatalogView {
            provider: name.clone(),
            catalog_source: "error".to_string(),
            runtime_supported: false,
            api_base: None,
            models: vec![],
            custom_models: vec![],
            warnings: vec![],
            error: Some(format!("Unknown provider '{}'", name)),
        };
        let response = ProviderCatalogService::new()
            .list_provider_models(&config, &name, runtime, None)
            .await
            .unwrap_or(fallback);
        let _ = reply.send(response);
    }

    pub(super) fn handle_resolve_provider(
        &self,
        model: String,
        preferred_provider: Option<String>,
        reply: oneshot::Sender<Option<String>>,
    ) {
        let config = self.loader.load().unwrap_or_default();
        let provider_id = ProviderCatalogService::new().resolve_provider_id(
            &config,
            &model,
            preferred_provider.as_deref(),
        );
        let _ = reply.send(provider_id);
    }

    pub(super) async fn handle_add_provider_model(
        &self,
        name: String,
        model: String,
        reply: oneshot::Sender<Result<(), String>>,
    ) {
        let mut config = match self.loader.load() {
            Ok(config) => config,
            Err(error) => {
                let _ = reply.send(Err(error.to_string()));
                return;
            }
        };
        let catalog = ProviderCatalogService::new();
        let result = catalog.add_provider_model(&mut config, &name, &model);
        if let Err(error) = result {
            let _ = reply.send(Err(error));
            return;
        }
        if config.agents.defaults.provider.as_deref() == Some(name.as_str()) {
            config.agents.defaults.model = model;
        }
        let response = self.loader.save(&config).map_err(|e| e.to_string());
        let _ = reply.send(response);
    }

    pub(super) async fn handle_delete_provider_model(
        &self,
        name: String,
        model_id: String,
        reply: oneshot::Sender<Result<(), String>>,
    ) {
        let mut config = match self.loader.load() {
            Ok(config) => config,
            Err(error) => {
                let _ = reply.send(Err(error.to_string()));
                return;
            }
        };
        let catalog = ProviderCatalogService::new();
        if let Err(error) = catalog.remove_provider_model(&mut config, &name, &model_id) {
            let _ = reply.send(Err(error));
            return;
        }
        if config.agents.defaults.provider.as_deref() == Some(name.as_str())
            && config.agents.defaults.model == model_id
        {
            match catalog
                .list_provider_models(&config, &name, false, None)
                .await
            {
                Ok(models) => {
                    if let Some(next_model) = models.models.first() {
                        config.agents.defaults.model = next_model.id.clone();
                    }
                }
                Err(error) => {
                    let _ = reply.send(Err(error));
                    return;
                }
            }
        }
        let response = self.loader.save(&config).map_err(|e| e.to_string());
        let _ = reply.send(response);
    }

    pub(super) async fn handle_create_provider(
        &self,
        payload: CustomProviderUpsert,
        reply: oneshot::Sender<Result<Option<ProviderView>, String>>,
    ) {
        let _ = reply.send(self.save_provider(payload).await);
    }

    pub(super) async fn handle_update_provider(
        &self,
        name: String,
        mut payload: CustomProviderUpsert,
        reply: oneshot::Sender<Result<Option<ProviderView>, String>>,
    ) {
        payload.id = name;
        let _ = reply.send(self.save_provider(payload).await);
    }

    pub(super) async fn handle_delete_provider(
        &self,
        name: String,
        reply: oneshot::Sender<Result<(), String>>,
    ) {
        let mut config = match self.loader.load() {
            Ok(config) => config,
            Err(error) => {
                let _ = reply.send(Err(error.to_string()));
                return;
            }
        };
        let catalog = ProviderCatalogService::new();
        if let Err(error) = catalog.delete_custom_provider(&mut config, &name) {
            let _ = reply.send(Err(error));
            return;
        }
        if config.agents.defaults.provider.as_deref() == Some(name.as_str()) {
            let fallback = catalog.list_provider_views(&config).into_iter().next();
            config.agents.defaults.provider = fallback.as_ref().map(|provider| provider.id.clone());
            if let Some(provider) = fallback {
                if let Some(model) = provider.default_model {
                    config.agents.defaults.model = model;
                }
            }
        }
        let response = self.loader.save(&config).map_err(|e| e.to_string());
        let _ = reply.send(response);
    }

    async fn save_provider(
        &self,
        payload: CustomProviderUpsert,
    ) -> Result<Option<ProviderView>, String> {
        let mut config = self.loader.load().map_err(|e| e.to_string())?;
        let provider_id = payload.id.clone();
        ProviderCatalogService::new()
            .save_custom_provider(&mut config, payload)
            .map_err(|e| e.to_string())?;
        self.loader.save(&config).map_err(|e| e.to_string())?;
        Ok(ProviderCatalogService::new().get_provider_view(&config, &provider_id))
    }
}