use crate::core::agent::{CompletionAction, PostToolAction, PreToolAction};
use crate::core::messages::Message;
use crate::core::retry::RetryAction;
use crate::core::tools::ToolDefinition;
use crate::error::AgentSdkError;
use async_trait::async_trait;
use serde_json::Value;
use std::borrow::Cow;
pub struct PluginContext {
world: hecs::World,
entity: hecs::Entity,
}
impl std::fmt::Debug for PluginContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PluginContext")
.field("entity", &self.entity)
.finish_non_exhaustive()
}
}
impl PluginContext {
pub(crate) fn into_parts(self) -> (hecs::World, hecs::Entity) {
(self.world, self.entity)
}
pub fn new(world: hecs::World, entity: hecs::Entity) -> Self {
Self { world, entity }
}
pub fn get<T: Send + Sync + 'static>(&self) -> Option<hecs::Ref<'_, T>> {
self.world.get::<&T>(self.entity).ok()
}
pub fn get_mut<T: Send + Sync + 'static>(&mut self) -> Option<hecs::RefMut<'_, T>> {
self.world.get::<&mut T>(self.entity).ok()
}
pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) {
if let Err(e) = self.world.insert_one(self.entity, val) {
tracing::warn!("Failed to insert component: {e}");
}
}
pub fn world(&self) -> &hecs::World {
&self.world
}
pub fn world_mut(&mut self) -> &mut hecs::World {
&mut self.world
}
}
#[async_trait]
pub trait AgentPlugin: Send + Sync {
fn name(&self) -> &'static str;
async fn init(&mut self, _ctx: &mut PluginContext) -> Result<(), AgentSdkError> {
Ok(())
}
async fn shutdown(&mut self, _ctx: &mut PluginContext) -> Result<(), AgentSdkError> {
Ok(())
}
fn on_text_delta(&mut self, _ctx: &mut PluginContext, _text: &str) {}
fn on_assistant_message(&mut self, _ctx: &mut PluginContext, _msg: &Message) {}
async fn on_iteration_start(&mut self, _ctx: &mut PluginContext, _iteration: usize) {}
async fn on_iteration_end(
&mut self,
_ctx: &mut PluginContext,
_iteration: usize,
_had_tool_calls: bool,
) {
}
async fn prepare_system_prompt(
&mut self,
_ctx: &mut PluginContext,
) -> Option<Cow<'static, str>> {
None
}
async fn on_tool_pre_execute(
&mut self,
_ctx: &mut PluginContext,
_id: &str,
_name: &str,
_args: &Value,
) -> PreToolAction {
PreToolAction::Proceed(None)
}
async fn on_tool_post_execute(
&mut self,
_ctx: &mut PluginContext,
_id: &str,
_name: &str,
_result: &Result<Value, String>,
) -> PostToolAction {
PostToolAction::Proceed(None)
}
async fn on_completion(&mut self, _ctx: &mut PluginContext, _text: &str) -> CompletionAction {
CompletionAction::Accept
}
async fn on_api_error(
&mut self,
_ctx: &mut PluginContext,
_error: &AgentSdkError,
) -> RetryAction {
RetryAction::GiveUp
}
fn tools(&self) -> Vec<ToolDefinition> {
Vec::new()
}
async fn on_user_message(&mut self, _ctx: &mut PluginContext, text: String) -> String {
text
}
async fn run_tool(
&mut self,
_ctx: &mut PluginContext,
_call: &PluginToolCall,
) -> Result<Value, String> {
Err(format!("run_tool not implemented for {}", self.name()))
}
}
#[derive(Debug, Clone)]
pub struct PluginToolCall {
pub id: String,
pub name: String,
pub arguments: Value,
}
pub trait PluginTools: Sized {
fn definitions() -> Vec<ToolDefinition>;
fn from_call(call: &PluginToolCall) -> Result<Self, String>;
}