1use serde::{Deserialize, Serialize};
30use std::collections::HashMap;
31
32use super::response::{ToolExecutionResponse, ToolSchema};
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct ToolExecuteParams {
37 #[serde(skip_serializing_if = "Option::is_none")]
39 pub slug: Option<String>,
40
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub allow_tracing: Option<bool>,
44
45 pub arguments: HashMap<String, serde_json::Value>,
47
48 #[serde(skip_serializing_if = "Option::is_none")]
50 pub connected_account_id: Option<String>,
51
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub custom_auth_params: Option<CustomAuthParams>,
55
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub custom_connection_data: Option<CustomConnectionData>,
59
60 #[serde(skip_serializing_if = "Option::is_none")]
62 pub entity_id: Option<String>,
63
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub text: Option<String>,
67
68 #[serde(skip_serializing_if = "Option::is_none")]
70 pub user_id: Option<String>,
71
72 #[serde(skip_serializing_if = "Option::is_none")]
74 pub version: Option<String>,
75
76 #[serde(skip_serializing_if = "Option::is_none")]
78 pub dangerously_skip_version_check: Option<bool>,
79}
80
81impl ToolExecuteParams {
82 pub fn new(slug: impl Into<String>, arguments: HashMap<String, serde_json::Value>) -> Self {
84 Self {
85 slug: Some(slug.into()),
86 allow_tracing: None,
87 arguments,
88 connected_account_id: None,
89 custom_auth_params: None,
90 custom_connection_data: None,
91 entity_id: None,
92 text: None,
93 user_id: None,
94 version: None,
95 dangerously_skip_version_check: None,
96 }
97 }
98
99 pub fn slug(&self) -> &str {
101 self.slug.as_ref().expect("Tool slug is required for execution")
102 }
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct CustomAuthParams {
108 #[serde(skip_serializing_if = "Option::is_none")]
110 pub base_url: Option<String>,
111
112 #[serde(skip_serializing_if = "Option::is_none")]
114 pub headers: Option<HashMap<String, String>>,
115
116 #[serde(skip_serializing_if = "Option::is_none")]
118 pub query_params: Option<HashMap<String, String>>,
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct CustomConnectionData {
124 #[serde(skip_serializing_if = "Option::is_none")]
126 pub auth_scheme: Option<String>,
127
128 #[serde(skip_serializing_if = "Option::is_none")]
130 pub parameters: Option<HashMap<String, serde_json::Value>>,
131}
132
133#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
135#[serde(rename_all = "snake_case")]
136pub enum ModifierType {
137 BeforeExecute,
139
140 AfterExecute,
142
143 Schema,
145
146 BeforeExecuteMeta,
148
149 AfterExecuteMeta,
151}
152
153pub trait BeforeExecute: Send + Sync {
155 fn modify(&self, tool: &str, toolkit: &str, params: ToolExecuteParams) -> ToolExecuteParams;
167}
168
169pub trait AfterExecute: Send + Sync {
171 fn modify(
183 &self,
184 tool: &str,
185 toolkit: &str,
186 response: ToolExecutionResponse,
187 ) -> ToolExecutionResponse;
188}
189
190pub trait SchemaModifier: Send + Sync {
192 fn modify(&self, tool: &str, toolkit: &str, schema: ToolSchema) -> ToolSchema;
204}
205
206pub trait BeforeExecuteMeta: Send + Sync {
208 fn modify(
221 &self,
222 tool: &str,
223 toolkit: &str,
224 session_id: &str,
225 params: HashMap<String, serde_json::Value>,
226 ) -> HashMap<String, serde_json::Value>;
227}
228
229pub trait AfterExecuteMeta: Send + Sync {
231 fn modify(
244 &self,
245 tool: &str,
246 toolkit: &str,
247 session_id: &str,
248 response: ToolExecutionResponse,
249 ) -> ToolExecutionResponse;
250}
251
252pub struct Modifier {
254 pub modifier_type: ModifierType,
256
257 pub tools: Vec<String>,
259
260 pub toolkits: Vec<String>,
262
263 modifier_fn: ModifierFunction,
265}
266
267enum ModifierFunction {
269 BeforeExecute(Box<dyn BeforeExecute>),
270 AfterExecute(Box<dyn AfterExecute>),
271 Schema(Box<dyn SchemaModifier>),
272 BeforeExecuteMeta(Box<dyn BeforeExecuteMeta>),
273 AfterExecuteMeta(Box<dyn AfterExecuteMeta>),
274}
275
276impl Modifier {
277 pub fn before_execute<F>(tools: Vec<String>, toolkits: Vec<String>, modifier: F) -> Self
279 where
280 F: BeforeExecute + 'static,
281 {
282 Self {
283 modifier_type: ModifierType::BeforeExecute,
284 tools,
285 toolkits,
286 modifier_fn: ModifierFunction::BeforeExecute(Box::new(modifier)),
287 }
288 }
289
290 pub fn after_execute<F>(tools: Vec<String>, toolkits: Vec<String>, modifier: F) -> Self
292 where
293 F: AfterExecute + 'static,
294 {
295 Self {
296 modifier_type: ModifierType::AfterExecute,
297 tools,
298 toolkits,
299 modifier_fn: ModifierFunction::AfterExecute(Box::new(modifier)),
300 }
301 }
302
303 pub fn schema<F>(tools: Vec<String>, toolkits: Vec<String>, modifier: F) -> Self
305 where
306 F: SchemaModifier + 'static,
307 {
308 Self {
309 modifier_type: ModifierType::Schema,
310 tools,
311 toolkits,
312 modifier_fn: ModifierFunction::Schema(Box::new(modifier)),
313 }
314 }
315
316 pub fn before_execute_meta<F>(tools: Vec<String>, toolkits: Vec<String>, modifier: F) -> Self
318 where
319 F: BeforeExecuteMeta + 'static,
320 {
321 Self {
322 modifier_type: ModifierType::BeforeExecuteMeta,
323 tools,
324 toolkits,
325 modifier_fn: ModifierFunction::BeforeExecuteMeta(Box::new(modifier)),
326 }
327 }
328
329 pub fn after_execute_meta<F>(tools: Vec<String>, toolkits: Vec<String>, modifier: F) -> Self
331 where
332 F: AfterExecuteMeta + 'static,
333 {
334 Self {
335 modifier_type: ModifierType::AfterExecuteMeta,
336 tools,
337 toolkits,
338 modifier_fn: ModifierFunction::AfterExecuteMeta(Box::new(modifier)),
339 }
340 }
341
342 fn should_apply(&self, tool: &str, toolkit: &str) -> bool {
344 if self.tools.is_empty() && self.toolkits.is_empty() {
346 return true;
347 }
348
349 self.tools.contains(&tool.to_string()) || self.toolkits.contains(&toolkit.to_string())
351 }
352
353 pub fn apply_to_params(
355 &self,
356 tool: &str,
357 toolkit: &str,
358 params: ToolExecuteParams,
359 ) -> Result<ToolExecuteParams, String> {
360 if !self.should_apply(tool, toolkit) {
361 return Ok(params);
362 }
363
364 match &self.modifier_fn {
365 ModifierFunction::BeforeExecute(modifier) => Ok(modifier.modify(tool, toolkit, params)),
366 _ => Err("Modifier type mismatch: expected BeforeExecute".to_string()),
367 }
368 }
369
370 pub fn apply_to_response(
372 &self,
373 tool: &str,
374 toolkit: &str,
375 response: ToolExecutionResponse,
376 ) -> Result<ToolExecutionResponse, String> {
377 if !self.should_apply(tool, toolkit) {
378 return Ok(response);
379 }
380
381 match &self.modifier_fn {
382 ModifierFunction::AfterExecute(modifier) => {
383 Ok(modifier.modify(tool, toolkit, response))
384 }
385 _ => Err("Modifier type mismatch: expected AfterExecute".to_string()),
386 }
387 }
388
389 pub fn apply_to_schema(
391 &self,
392 tool: &str,
393 toolkit: &str,
394 schema: ToolSchema,
395 ) -> Result<ToolSchema, String> {
396 if !self.should_apply(tool, toolkit) {
397 return Ok(schema);
398 }
399
400 match &self.modifier_fn {
401 ModifierFunction::Schema(modifier) => Ok(modifier.modify(tool, toolkit, schema)),
402 _ => Err("Modifier type mismatch: expected Schema".to_string()),
403 }
404 }
405
406 pub fn apply_to_meta_params(
408 &self,
409 tool: &str,
410 toolkit: &str,
411 session_id: &str,
412 params: HashMap<String, serde_json::Value>,
413 ) -> Result<HashMap<String, serde_json::Value>, String> {
414 if !self.should_apply(tool, toolkit) {
415 return Ok(params);
416 }
417
418 match &self.modifier_fn {
419 ModifierFunction::BeforeExecuteMeta(modifier) => {
420 Ok(modifier.modify(tool, toolkit, session_id, params))
421 }
422 _ => Err("Modifier type mismatch: expected BeforeExecuteMeta".to_string()),
423 }
424 }
425
426 pub fn apply_to_meta_response(
428 &self,
429 tool: &str,
430 toolkit: &str,
431 session_id: &str,
432 response: ToolExecutionResponse,
433 ) -> Result<ToolExecutionResponse, String> {
434 if !self.should_apply(tool, toolkit) {
435 return Ok(response);
436 }
437
438 match &self.modifier_fn {
439 ModifierFunction::AfterExecuteMeta(modifier) => {
440 Ok(modifier.modify(tool, toolkit, session_id, response))
441 }
442 _ => Err("Modifier type mismatch: expected AfterExecuteMeta".to_string()),
443 }
444 }
445}
446
447pub type Modifiers = Vec<Modifier>;
449
450pub fn apply_before_execute_modifiers(
452 modifiers: &Modifiers,
453 tool: &str,
454 toolkit: &str,
455 mut params: ToolExecuteParams,
456) -> Result<ToolExecuteParams, String> {
457 for modifier in modifiers {
458 if modifier.modifier_type == ModifierType::BeforeExecute {
459 params = modifier.apply_to_params(tool, toolkit, params)?;
460 }
461 }
462 Ok(params)
463}
464
465pub fn apply_after_execute_modifiers(
467 modifiers: &Modifiers,
468 tool: &str,
469 toolkit: &str,
470 mut response: ToolExecutionResponse,
471) -> Result<ToolExecutionResponse, String> {
472 for modifier in modifiers {
473 if modifier.modifier_type == ModifierType::AfterExecute {
474 response = modifier.apply_to_response(tool, toolkit, response)?;
475 }
476 }
477 Ok(response)
478}
479
480pub fn apply_schema_modifiers(
482 modifiers: &Modifiers,
483 tool: &str,
484 toolkit: &str,
485 mut schema: ToolSchema,
486) -> Result<ToolSchema, String> {
487 for modifier in modifiers {
488 if modifier.modifier_type == ModifierType::Schema {
489 schema = modifier.apply_to_schema(tool, toolkit, schema)?;
490 }
491 }
492 Ok(schema)
493}
494
495pub fn apply_before_execute_meta_modifiers(
497 modifiers: &Modifiers,
498 tool: &str,
499 toolkit: &str,
500 session_id: &str,
501 mut params: HashMap<String, serde_json::Value>,
502) -> Result<HashMap<String, serde_json::Value>, String> {
503 for modifier in modifiers {
504 if modifier.modifier_type == ModifierType::BeforeExecuteMeta {
505 params = modifier.apply_to_meta_params(tool, toolkit, session_id, params)?;
506 }
507 }
508 Ok(params)
509}
510
511pub fn apply_after_execute_meta_modifiers(
513 modifiers: &Modifiers,
514 tool: &str,
515 toolkit: &str,
516 session_id: &str,
517 mut response: ToolExecutionResponse,
518) -> Result<ToolExecutionResponse, String> {
519 for modifier in modifiers {
520 if modifier.modifier_type == ModifierType::AfterExecuteMeta {
521 response = modifier.apply_to_meta_response(tool, toolkit, session_id, response)?;
522 }
523 }
524 Ok(response)
525}