use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use super::response::{ToolExecutionResponse, ToolSchema};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolExecuteParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub slug: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_tracing: Option<bool>,
pub arguments: HashMap<String, serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub connected_account_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_auth_params: Option<CustomAuthParams>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_connection_data: Option<CustomConnectionData>,
#[serde(skip_serializing_if = "Option::is_none")]
pub entity_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dangerously_skip_version_check: Option<bool>,
}
impl ToolExecuteParams {
pub fn new(slug: impl Into<String>, arguments: HashMap<String, serde_json::Value>) -> Self {
Self {
slug: Some(slug.into()),
allow_tracing: None,
arguments,
connected_account_id: None,
custom_auth_params: None,
custom_connection_data: None,
entity_id: None,
text: None,
user_id: None,
version: None,
dangerously_skip_version_check: None,
}
}
pub fn slug(&self) -> &str {
self.slug.as_ref().expect("Tool slug is required for execution")
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CustomAuthParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub base_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub headers: Option<HashMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_params: Option<HashMap<String, String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CustomConnectionData {
#[serde(skip_serializing_if = "Option::is_none")]
pub auth_scheme: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parameters: Option<HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ModifierType {
BeforeExecute,
AfterExecute,
Schema,
BeforeExecuteMeta,
AfterExecuteMeta,
}
pub trait BeforeExecute: Send + Sync {
fn modify(&self, tool: &str, toolkit: &str, params: ToolExecuteParams) -> ToolExecuteParams;
}
pub trait AfterExecute: Send + Sync {
fn modify(
&self,
tool: &str,
toolkit: &str,
response: ToolExecutionResponse,
) -> ToolExecutionResponse;
}
pub trait SchemaModifier: Send + Sync {
fn modify(&self, tool: &str, toolkit: &str, schema: ToolSchema) -> ToolSchema;
}
pub trait BeforeExecuteMeta: Send + Sync {
fn modify(
&self,
tool: &str,
toolkit: &str,
session_id: &str,
params: HashMap<String, serde_json::Value>,
) -> HashMap<String, serde_json::Value>;
}
pub trait AfterExecuteMeta: Send + Sync {
fn modify(
&self,
tool: &str,
toolkit: &str,
session_id: &str,
response: ToolExecutionResponse,
) -> ToolExecutionResponse;
}
pub struct Modifier {
pub modifier_type: ModifierType,
pub tools: Vec<String>,
pub toolkits: Vec<String>,
modifier_fn: ModifierFunction,
}
enum ModifierFunction {
BeforeExecute(Box<dyn BeforeExecute>),
AfterExecute(Box<dyn AfterExecute>),
Schema(Box<dyn SchemaModifier>),
BeforeExecuteMeta(Box<dyn BeforeExecuteMeta>),
AfterExecuteMeta(Box<dyn AfterExecuteMeta>),
}
impl Modifier {
pub fn before_execute<F>(tools: Vec<String>, toolkits: Vec<String>, modifier: F) -> Self
where
F: BeforeExecute + 'static,
{
Self {
modifier_type: ModifierType::BeforeExecute,
tools,
toolkits,
modifier_fn: ModifierFunction::BeforeExecute(Box::new(modifier)),
}
}
pub fn after_execute<F>(tools: Vec<String>, toolkits: Vec<String>, modifier: F) -> Self
where
F: AfterExecute + 'static,
{
Self {
modifier_type: ModifierType::AfterExecute,
tools,
toolkits,
modifier_fn: ModifierFunction::AfterExecute(Box::new(modifier)),
}
}
pub fn schema<F>(tools: Vec<String>, toolkits: Vec<String>, modifier: F) -> Self
where
F: SchemaModifier + 'static,
{
Self {
modifier_type: ModifierType::Schema,
tools,
toolkits,
modifier_fn: ModifierFunction::Schema(Box::new(modifier)),
}
}
pub fn before_execute_meta<F>(tools: Vec<String>, toolkits: Vec<String>, modifier: F) -> Self
where
F: BeforeExecuteMeta + 'static,
{
Self {
modifier_type: ModifierType::BeforeExecuteMeta,
tools,
toolkits,
modifier_fn: ModifierFunction::BeforeExecuteMeta(Box::new(modifier)),
}
}
pub fn after_execute_meta<F>(tools: Vec<String>, toolkits: Vec<String>, modifier: F) -> Self
where
F: AfterExecuteMeta + 'static,
{
Self {
modifier_type: ModifierType::AfterExecuteMeta,
tools,
toolkits,
modifier_fn: ModifierFunction::AfterExecuteMeta(Box::new(modifier)),
}
}
fn should_apply(&self, tool: &str, toolkit: &str) -> bool {
if self.tools.is_empty() && self.toolkits.is_empty() {
return true;
}
self.tools.contains(&tool.to_string()) || self.toolkits.contains(&toolkit.to_string())
}
pub fn apply_to_params(
&self,
tool: &str,
toolkit: &str,
params: ToolExecuteParams,
) -> Result<ToolExecuteParams, String> {
if !self.should_apply(tool, toolkit) {
return Ok(params);
}
match &self.modifier_fn {
ModifierFunction::BeforeExecute(modifier) => Ok(modifier.modify(tool, toolkit, params)),
_ => Err("Modifier type mismatch: expected BeforeExecute".to_string()),
}
}
pub fn apply_to_response(
&self,
tool: &str,
toolkit: &str,
response: ToolExecutionResponse,
) -> Result<ToolExecutionResponse, String> {
if !self.should_apply(tool, toolkit) {
return Ok(response);
}
match &self.modifier_fn {
ModifierFunction::AfterExecute(modifier) => {
Ok(modifier.modify(tool, toolkit, response))
}
_ => Err("Modifier type mismatch: expected AfterExecute".to_string()),
}
}
pub fn apply_to_schema(
&self,
tool: &str,
toolkit: &str,
schema: ToolSchema,
) -> Result<ToolSchema, String> {
if !self.should_apply(tool, toolkit) {
return Ok(schema);
}
match &self.modifier_fn {
ModifierFunction::Schema(modifier) => Ok(modifier.modify(tool, toolkit, schema)),
_ => Err("Modifier type mismatch: expected Schema".to_string()),
}
}
pub fn apply_to_meta_params(
&self,
tool: &str,
toolkit: &str,
session_id: &str,
params: HashMap<String, serde_json::Value>,
) -> Result<HashMap<String, serde_json::Value>, String> {
if !self.should_apply(tool, toolkit) {
return Ok(params);
}
match &self.modifier_fn {
ModifierFunction::BeforeExecuteMeta(modifier) => {
Ok(modifier.modify(tool, toolkit, session_id, params))
}
_ => Err("Modifier type mismatch: expected BeforeExecuteMeta".to_string()),
}
}
pub fn apply_to_meta_response(
&self,
tool: &str,
toolkit: &str,
session_id: &str,
response: ToolExecutionResponse,
) -> Result<ToolExecutionResponse, String> {
if !self.should_apply(tool, toolkit) {
return Ok(response);
}
match &self.modifier_fn {
ModifierFunction::AfterExecuteMeta(modifier) => {
Ok(modifier.modify(tool, toolkit, session_id, response))
}
_ => Err("Modifier type mismatch: expected AfterExecuteMeta".to_string()),
}
}
}
pub type Modifiers = Vec<Modifier>;
pub fn apply_before_execute_modifiers(
modifiers: &Modifiers,
tool: &str,
toolkit: &str,
mut params: ToolExecuteParams,
) -> Result<ToolExecuteParams, String> {
for modifier in modifiers {
if modifier.modifier_type == ModifierType::BeforeExecute {
params = modifier.apply_to_params(tool, toolkit, params)?;
}
}
Ok(params)
}
pub fn apply_after_execute_modifiers(
modifiers: &Modifiers,
tool: &str,
toolkit: &str,
mut response: ToolExecutionResponse,
) -> Result<ToolExecutionResponse, String> {
for modifier in modifiers {
if modifier.modifier_type == ModifierType::AfterExecute {
response = modifier.apply_to_response(tool, toolkit, response)?;
}
}
Ok(response)
}
pub fn apply_schema_modifiers(
modifiers: &Modifiers,
tool: &str,
toolkit: &str,
mut schema: ToolSchema,
) -> Result<ToolSchema, String> {
for modifier in modifiers {
if modifier.modifier_type == ModifierType::Schema {
schema = modifier.apply_to_schema(tool, toolkit, schema)?;
}
}
Ok(schema)
}
pub fn apply_before_execute_meta_modifiers(
modifiers: &Modifiers,
tool: &str,
toolkit: &str,
session_id: &str,
mut params: HashMap<String, serde_json::Value>,
) -> Result<HashMap<String, serde_json::Value>, String> {
for modifier in modifiers {
if modifier.modifier_type == ModifierType::BeforeExecuteMeta {
params = modifier.apply_to_meta_params(tool, toolkit, session_id, params)?;
}
}
Ok(params)
}
pub fn apply_after_execute_meta_modifiers(
modifiers: &Modifiers,
tool: &str,
toolkit: &str,
session_id: &str,
mut response: ToolExecutionResponse,
) -> Result<ToolExecutionResponse, String> {
for modifier in modifiers {
if modifier.modifier_type == ModifierType::AfterExecuteMeta {
response = modifier.apply_to_meta_response(tool, toolkit, session_id, response)?;
}
}
Ok(response)
}