pub mod capability;
pub mod error;
pub mod payload;
#[cfg(feature = "agent")]
pub mod impls;
#[cfg(feature = "agent")]
pub mod retry;
#[cfg(feature = "agent")]
pub mod persona;
#[cfg(feature = "agent")]
pub mod history;
#[cfg(feature = "agent")]
pub mod retrieval;
#[cfg(feature = "agent")]
pub mod payload_message;
#[cfg(feature = "agent")]
pub mod chat;
#[cfg(feature = "agent")]
pub mod dialogue;
#[cfg(feature = "agent")]
pub mod expertise;
#[cfg(feature = "agent")]
pub mod expertise_agent;
#[cfg(feature = "agent")]
pub mod env_context;
#[cfg(feature = "agent")]
pub mod detected_context;
#[cfg(feature = "agent")]
pub mod execution_context;
#[cfg(feature = "agent")]
pub mod context_detector;
#[cfg(feature = "agent")]
pub mod rule_based_detector;
#[cfg(feature = "agent")]
pub mod agent_based_detector;
#[derive(Debug, Clone, Copy, Default)]
pub enum ExecutionProfile {
Creative,
#[default]
Balanced,
Deterministic,
}
pub use capability::Capability;
pub use error::{AgentError, ErrorMetadata, ParseErrorReason, RichErrorBuilder};
#[cfg(feature = "agent")]
pub use expertise_agent::ExpertiseAgent;
pub use payload::{Payload, PayloadContent};
#[cfg(feature = "agent")]
pub use payload_message::{
PayloadMessage, RelatedParticipant, RelatedPayloadMessage, SpeakerRelation,
participant_relation,
};
#[cfg(feature = "agent")]
pub use env_context::{EnvContext, JournalSummary, StepInfo};
#[cfg(feature = "agent")]
pub use detected_context::{ConfidenceScores, DetectedContext};
#[cfg(feature = "agent")]
pub use execution_context::{ExecutionContext, ExecutionContextExt};
#[cfg(feature = "agent")]
pub use context_detector::{ContextDetector, DetectContextExt};
#[cfg(feature = "agent")]
pub use rule_based_detector::RuleBasedDetector;
#[cfg(feature = "agent")]
pub use agent_based_detector::AgentBasedDetector;
use crate::prompt::ToPrompt;
use async_trait::async_trait;
use serde::{Serialize, de::DeserializeOwned};
use std::sync::Arc;
pub trait ToExpertise: ToPrompt {
fn description(&self) -> &str;
fn capabilities(&self) -> Vec<Capability> {
Vec::new()
}
}
impl ToExpertise for &str {
fn description(&self) -> &str {
self
}
}
impl ToExpertise for String {
fn description(&self) -> &str {
self.as_str()
}
}
#[derive(Debug, Clone)]
pub enum AgentOutput {
Success(serde_json::Value),
RequiresApproval {
message_for_human: String,
current_payload: serde_json::Value,
},
}
#[async_trait]
pub trait Agent: Send + Sync {
type Output: Serialize + DeserializeOwned;
type Expertise: ToExpertise;
fn expertise(&self) -> &Self::Expertise;
fn description(&self) -> &str {
self.expertise().description()
}
async fn execute(&self, intent: Payload) -> Result<Self::Output, AgentError>;
fn name(&self) -> String {
std::any::type_name::<Self>()
.split("::")
.last()
.unwrap_or("UnknownAgent")
.to_string()
}
async fn is_available(&self) -> Result<(), AgentError> {
Ok(())
}
fn capabilities(&self) -> Option<Vec<Capability>> {
let caps = self.expertise().capabilities();
if caps.is_empty() { None } else { Some(caps) }
}
}
pub struct AnyAgent<T: Serialize + DeserializeOwned> {
inner: Box<dyn DynamicAgentInternal<T>>,
description: String,
capabilities: Option<Vec<Capability>>,
}
impl<T: Serialize + DeserializeOwned> AnyAgent<T> {
pub fn new<A: Agent<Output = T> + 'static>(agent: A) -> Self {
let description = agent.description().to_string();
let capabilities = agent.capabilities();
Self {
inner: Box::new(agent),
description,
capabilities,
}
}
pub fn boxed<A: Agent<Output = T> + 'static>(agent: A) -> Box<Self> {
Box::new(Self::new(agent))
}
pub fn arc<A: Agent<Output = T> + 'static>(agent: A) -> std::sync::Arc<Self> {
std::sync::Arc::new(Self::new(agent))
}
}
#[async_trait]
impl<T: Serialize + DeserializeOwned> Agent for AnyAgent<T> {
type Output = T;
type Expertise = String;
fn expertise(&self) -> &String {
&self.description
}
fn description(&self) -> &str {
&self.description
}
fn capabilities(&self) -> Option<Vec<Capability>> {
self.capabilities.clone()
}
async fn execute(&self, intent: Payload) -> Result<T, AgentError> {
self.inner.execute(intent).await
}
fn name(&self) -> String {
self.inner.name()
}
async fn is_available(&self) -> Result<(), AgentError> {
self.inner.is_available().await
}
}
#[deprecated(
since = "0.56.0",
note = "Use Box<AnyAgent<T>> or Arc<AnyAgent<T>> instead"
)]
pub type BoxedAgent<T, E = String> = Box<dyn Agent<Output = T, Expertise = E>>;
pub fn normalize_string_output(response: &str) -> String {
use crate::extract::{ExtractionStrategy, FlexibleExtractor};
if let Ok(extracted) = crate::extract_json(response) {
if let Ok(unquoted) = serde_json::from_str::<String>(&extracted) {
return unquoted;
}
return extracted;
}
let extractor = FlexibleExtractor::new();
let mut strategies = FlexibleExtractor::standard_extraction_strategies();
strategies.push(ExtractionStrategy::OriginalText);
let extracted = extractor
.extract_with_strategies(response, &strategies)
.unwrap_or_else(|_| response.to_string());
if let Ok(unquoted) = serde_json::from_str::<String>(&extracted) {
return unquoted;
}
extracted
}
#[async_trait]
pub trait DynamicAgent: Send + Sync {
async fn execute_dynamic(&self, intent: Payload) -> Result<AgentOutput, AgentError>;
fn name(&self) -> String;
fn description(&self) -> &str;
#[deprecated(since = "0.56.0", note = "Use description() instead")]
fn expertise(&self) -> &str {
self.description()
}
async fn is_available(&self) -> Result<(), AgentError> {
Ok(())
}
fn capabilities(&self) -> Option<Vec<Capability>> {
None
}
fn try_to_prompt(&self, _json: &serde_json::Value) -> Option<String> {
None
}
}
type ToPromptFn = Box<dyn Fn(&serde_json::Value) -> Option<String> + Send + Sync>;
pub struct AgentAdapter<T: Serialize + DeserializeOwned> {
inner: Box<dyn DynamicAgentInternal<T>>,
try_to_prompt_fn: Option<ToPromptFn>,
}
#[async_trait]
trait DynamicAgentInternal<T>: Send + Sync {
async fn execute(&self, intent: Payload) -> Result<T, AgentError>;
fn name(&self) -> String;
fn description(&self) -> &str;
async fn is_available(&self) -> Result<(), AgentError>;
fn capabilities(&self) -> Option<Vec<Capability>>;
}
#[async_trait]
impl<T, A> DynamicAgentInternal<T> for A
where
T: Serialize + DeserializeOwned,
A: Agent<Output = T> + Send + Sync,
{
async fn execute(&self, intent: Payload) -> Result<T, AgentError> {
Agent::execute(self, intent).await
}
fn name(&self) -> String {
Agent::name(self)
}
fn description(&self) -> &str {
Agent::description(self)
}
async fn is_available(&self) -> Result<(), AgentError> {
Agent::is_available(self).await
}
fn capabilities(&self) -> Option<Vec<Capability>> {
Agent::capabilities(self)
}
}
impl<T: Serialize + DeserializeOwned> AgentAdapter<T> {
pub fn new(agent: impl Agent<Output = T> + 'static) -> Self {
Self {
inner: Box::new(agent),
try_to_prompt_fn: None,
}
}
pub fn with_to_prompt(
agent: impl Agent<Output = T> + 'static,
to_prompt_fn: impl Fn(&T) -> String + Send + Sync + 'static,
) -> Self {
Self {
inner: Box::new(agent),
try_to_prompt_fn: Some(Box::new(move |json| {
serde_json::from_value::<T>(json.clone())
.ok()
.map(|output| to_prompt_fn(&output))
})),
}
}
}
#[async_trait]
impl<T: Serialize + DeserializeOwned> DynamicAgent for AgentAdapter<T> {
async fn execute_dynamic(&self, intent: Payload) -> Result<AgentOutput, AgentError> {
let output = self.inner.execute(intent).await?;
let json_value = serde_json::to_value(output)
.map_err(|e| AgentError::SerializationFailed(e.to_string()))?;
Ok(AgentOutput::Success(json_value))
}
fn name(&self) -> String {
self.inner.name()
}
fn description(&self) -> &str {
self.inner.description()
}
async fn is_available(&self) -> Result<(), AgentError> {
self.inner.is_available().await
}
fn capabilities(&self) -> Option<Vec<Capability>> {
self.inner.capabilities()
}
fn try_to_prompt(&self, json: &serde_json::Value) -> Option<String> {
self.try_to_prompt_fn.as_ref().and_then(|f| f(json))
}
}
#[async_trait]
impl<T: Agent + ?Sized> Agent for Box<T>
where
T::Output: Send,
{
type Output = T::Output;
type Expertise = T::Expertise;
fn expertise(&self) -> &T::Expertise {
(**self).expertise()
}
fn description(&self) -> &str {
(**self).description()
}
fn capabilities(&self) -> Option<Vec<Capability>> {
(**self).capabilities()
}
async fn execute(&self, intent: Payload) -> Result<Self::Output, AgentError> {
(**self).execute(intent).await
}
fn name(&self) -> String {
(**self).name()
}
async fn is_available(&self) -> Result<(), AgentError> {
(**self).is_available().await
}
}
#[async_trait]
impl<T: Agent + ?Sized> Agent for Arc<T>
where
T::Output: Send,
{
type Output = T::Output;
type Expertise = T::Expertise;
fn expertise(&self) -> &T::Expertise {
(**self).expertise()
}
fn description(&self) -> &str {
(**self).description()
}
fn capabilities(&self) -> Option<Vec<Capability>> {
(**self).capabilities()
}
async fn execute(&self, intent: Payload) -> Result<Self::Output, AgentError> {
(**self).execute(intent).await
}
fn name(&self) -> String {
(**self).name()
}
async fn is_available(&self) -> Result<(), AgentError> {
(**self).is_available().await
}
}