use std::fmt;
use std::time::Duration;
use crate::agent::McpServer;
use crate::caps::ToolPolicy;
use crate::id::{ChannelId, ConversationKey, UserId, UserRef};
use crate::message::Attachment;
use crate::secret::Secret;
use crate::{BoxError, async_trait};
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum KnowledgeError {
#[error("knowledge bundle: {0}")]
Bundle(#[source] BoxError),
#[error("knowledge error: {0}")]
Other(#[source] BoxError),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Requester {
pub conversation: ConversationKey,
pub user: UserRef,
pub internal: bool,
pub person: Option<Person>,
pub personal: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Person {
pub id: String,
pub accounts: Vec<(ChannelId, UserId)>,
}
#[derive(Debug, Clone, Copy)]
pub struct RunInfo<'a> {
pub tools: ToolPolicy,
pub ttl: Duration,
pub attachments: &'a [Attachment],
pub admin: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct KnowledgeContext {
pub persona: String,
pub catalog: String,
pub user_profile: Option<String>,
}
pub struct RunGrant {
pub mcp: Vec<McpServer>,
pub env: Vec<(String, Secret<String>)>,
_revoke_on_drop: Box<dyn Send + Sync>,
}
impl RunGrant {
pub fn new(
mcp: Vec<McpServer>,
env: Vec<(String, Secret<String>)>,
guard: impl Send + Sync + 'static,
) -> Self {
Self {
mcp,
env,
_revoke_on_drop: Box::new(guard),
}
}
pub fn none() -> Self {
Self::new(Vec::new(), Vec::new(), ())
}
}
impl fmt::Debug for RunGrant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RunGrant")
.field("mcp", &self.mcp)
.field("env", &self.env)
.finish_non_exhaustive()
}
}
#[async_trait]
pub trait KnowledgeProvider: Send + Sync {
async fn context(&self, who: &Requester) -> Result<KnowledgeContext, KnowledgeError>;
async fn grant(&self, who: &Requester, run: &RunInfo<'_>) -> Result<RunGrant, KnowledgeError>;
async fn excerpts(&self, who: &Requester, query: &str) -> Result<String, KnowledgeError>;
}