#![allow(clippy::pedantic)]
use super::extension::ExtensionPoint;
use super::store::RunStore;
use behest_provider::{ChatProvider, EmbeddingProvider};
use behest_store::{ArtifactStore, EmbeddingStore, ExecutionStore, SessionStore};
#[cfg(feature = "queue")]
use crate::event_publisher::EventPublisher;
use super::event_store::RuntimeEventStore;
use super::invocation::SessionDataStore;
use super::snapshot::SnapshotStore;
#[derive(Clone, Default)]
pub struct Extensions {
pub chat_providers: ExtensionPoint<dyn ChatProvider>,
pub embedding_providers: ExtensionPoint<dyn EmbeddingProvider>,
pub tools: ExtensionPoint<dyn behest_tool::Tool>,
pub context_adapters: ExtensionPoint<dyn behest_context::ContextAdapter>,
pub session_stores: ExtensionPoint<dyn SessionStore>,
pub execution_stores: ExtensionPoint<dyn ExecutionStore>,
pub embedding_stores: ExtensionPoint<dyn EmbeddingStore>,
pub artifact_stores: ExtensionPoint<dyn ArtifactStore>,
pub run_stores: ExtensionPoint<dyn RunStore>,
#[cfg(feature = "queue")]
pub event_publishers: ExtensionPoint<dyn EventPublisher>,
pub session_data_stores: ExtensionPoint<dyn SessionDataStore>,
pub runtime_event_stores: ExtensionPoint<dyn RuntimeEventStore>,
pub snapshot_stores: ExtensionPoint<dyn SnapshotStore>,
}
impl Extensions {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn populated_categories(&self) -> usize {
macro_rules! count {
($n:ident, $($field:ident),+ $(,)?) => {
$( if !self.$field.is_empty() { $n += 1; } )+
};
}
let mut n = 0;
count!(
n,
chat_providers,
embedding_providers,
tools,
context_adapters
);
count!(
n,
session_stores,
execution_stores,
embedding_stores,
artifact_stores,
run_stores
);
#[cfg(feature = "queue")]
if !self.event_publishers.is_empty() {
n += 1;
}
count!(
n,
session_data_stores,
runtime_event_stores,
snapshot_stores
);
n
}
}
impl std::fmt::Debug for Extensions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Extensions")
.field("chat_providers", &self.chat_providers.names())
.field("embedding_providers", &self.embedding_providers.names())
.field("tools", &self.tools.names())
.field("context_adapters", &self.context_adapters.names())
.field("session_stores", &self.session_stores.names())
.field("execution_stores", &self.execution_stores.names())
.field("embedding_stores", &self.embedding_stores.names())
.field("artifact_stores", &self.artifact_stores.names())
.field("run_stores", &self.run_stores.names())
.field("session_data_stores", &self.session_data_stores.names())
.field("runtime_event_stores", &self.runtime_event_stores.names())
.field("snapshot_stores", &self.snapshot_stores.names())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_extensions_reports_zero_populated() {
let exts = Extensions::new();
assert_eq!(exts.populated_categories(), 0);
}
#[test]
fn clone_shares_state() {
let exts = Extensions::new();
let exts2 = exts.clone();
assert_eq!(exts.populated_categories(), exts2.populated_categories());
}
}