Skip to main content

ares/agents/
context_provider.rs

1//! External context injection for agents.
2//!
3//! The `ContextProvider` trait allows external systems to inject context
4//! into agent calls before LLM invocation. This is the extension point
5//! that separates generic ARES from managed platform features.
6//!
7//! ## OSS Mode
8//!
9//! By default, ARES uses `NoOpContextProvider` which returns `None`.
10//! Agents run with only their system prompt — no external context.
11//!
12//! ## Managed Mode
13//!
14//! Platform extensions (e.g., dirmacs-core) implement `ContextProvider`
15//! to inject knowledge states, gap constraints, or any external context
16//! into the system prompt before every LLM call.
17
18use async_trait::async_trait;
19
20/// Trait for injecting external context into agent calls.
21///
22/// Called before every LLM invocation with the agent name and tenant ID.
23/// Returns `None` if no external context is available.
24#[async_trait]
25pub trait ContextProvider: Send + Sync + 'static {
26    /// Get context for a specific agent and tenant.
27    async fn get_context(
28        &self,
29        agent_name: &str,
30        tenant_id: &str,
31    ) -> Option<String>;
32}
33
34/// Default: no external context (pure OSS mode).
35///
36/// Agents run with only their configured system prompt.
37pub struct NoOpContextProvider;
38
39#[async_trait]
40impl ContextProvider for NoOpContextProvider {
41    async fn get_context(&self, _agent_name: &str, _tenant_id: &str) -> Option<String> {
42        None
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[tokio::test]
51    async fn test_noop_returns_none() {
52        let provider = NoOpContextProvider;
53        let result = provider.get_context("any_agent", "any_tenant").await;
54        assert!(result.is_none(), "NoOp should always return None");
55    }
56
57    #[tokio::test]
58    async fn test_noop_is_send_sync() {
59        // Verify the trait object can be shared across threads
60        let provider: Box<dyn ContextProvider> = Box::new(NoOpContextProvider);
61        let arc = std::sync::Arc::new(provider);
62        let _clone = arc.clone();
63    }
64}