use async_trait::async_trait;
use std::path::PathBuf;
use uuid::Uuid;
use crate::agent::engine::{EngineConfig, EnginePreferenceStore};
use crate::agent::skills::EnabledSkillsStore;
use pensieve_core::credentials::{Credential, CredentialStore};
use pensieve_core::tenant::TenantId;
pub struct NullEnginePreferenceStore;
#[async_trait]
impl EnginePreferenceStore for NullEnginePreferenceStore {
async fn get(&self) -> anyhow::Result<EngineConfig> {
anyhow::bail!("no agent engine configured (local mode — set one to enable Ask AI)")
}
async fn put(&self, _cfg: &EngineConfig) -> anyhow::Result<()> {
Ok(())
}
}
pub struct FileEnginePreferenceStore {
path: PathBuf,
}
impl FileEnginePreferenceStore {
pub fn new(path: impl Into<PathBuf>) -> Self {
Self { path: path.into() }
}
}
#[async_trait]
impl EnginePreferenceStore for FileEnginePreferenceStore {
async fn get(&self) -> anyhow::Result<EngineConfig> {
let raw = tokio::fs::read_to_string(&self.path).await.map_err(|_| {
anyhow::anyhow!(
"no agent engine configured — set one in Settings → Agent engine to enable Ask AI"
)
})?;
Ok(serde_json::from_str(&raw)?)
}
async fn put(&self, cfg: &EngineConfig) -> anyhow::Result<()> {
if let Some(dir) = self.path.parent() {
tokio::fs::create_dir_all(dir).await?;
}
tokio::fs::write(&self.path, serde_json::to_string_pretty(cfg)?).await?;
Ok(())
}
}
pub struct NullEnabledSkillsStore;
#[async_trait]
impl EnabledSkillsStore for NullEnabledSkillsStore {
async fn get(&self) -> anyhow::Result<Vec<String>> {
Ok(Vec::new())
}
async fn put(&self, _skills: &[String]) -> anyhow::Result<()> {
Ok(())
}
}
pub struct FileEnabledSkillsStore {
path: PathBuf,
}
impl FileEnabledSkillsStore {
pub fn new(path: impl Into<PathBuf>) -> Self {
Self { path: path.into() }
}
}
#[async_trait]
impl EnabledSkillsStore for FileEnabledSkillsStore {
async fn get(&self) -> anyhow::Result<Vec<String>> {
match tokio::fs::read_to_string(&self.path).await {
Ok(raw) => Ok(serde_json::from_str(&raw)?),
Err(_) => Ok(Vec::new()),
}
}
async fn put(&self, skills: &[String]) -> anyhow::Result<()> {
if let Some(dir) = self.path.parent() {
tokio::fs::create_dir_all(dir).await?;
}
tokio::fs::write(&self.path, serde_json::to_string_pretty(&skills)?).await?;
Ok(())
}
}
pub struct NullCredentialStore;
#[async_trait]
impl CredentialStore for NullCredentialStore {
async fn get(&self, _tenant: TenantId, _id: Uuid) -> anyhow::Result<Credential> {
anyhow::bail!("no credential store in local mode")
}
}