use crate::core::agent::{CompletionAction, PostToolAction, PreToolAction, ToolErrorAction};
use crate::core::messages::{Message, Messages};
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 {
pub world: hecs::World,
pub 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 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) {}
async fn shutdown(&mut self, _ctx: &mut PluginContext) {}
async fn on_text_delta(&mut self, _ctx: &PluginContext, _text: &str) {}
async fn on_model_response_completed(&mut self, _ctx: &PluginContext, _msg: &Message) {}
async fn prepare_system_prompt(
&mut self,
_ctx: &PluginContext,
_history: &Messages,
) -> Option<Cow<'static, str>> {
None
}
async fn on_tool_pre_execute(
&mut self,
_ctx: &PluginContext,
_id: &str,
_name: &str,
_args: &Value,
) -> PreToolAction {
PreToolAction::Continue(None)
}
async fn on_tool_post_execute(
&mut self,
_ctx: &PluginContext,
_id: &str,
_name: &str,
_result: &Value,
) -> PostToolAction {
PostToolAction::Continue(None)
}
async fn on_tool_error(
&mut self,
_ctx: &PluginContext,
_id: &str,
_name: &str,
_error: &str,
) -> ToolErrorAction {
ToolErrorAction::Continue(None)
}
async fn on_completion(&mut self, _ctx: &PluginContext, _text: String) -> CompletionAction {
CompletionAction::Accept(None)
}
async fn on_api_error(&mut self, _ctx: &PluginContext, _error: &AgentSdkError) -> RetryAction {
RetryAction::DoNotRetry
}
fn tools(&self) -> Vec<ToolDefinition> {
Vec::new()
}
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,
}