git_iris/agents/
debug_tool.rs

1//! Debug wrapper for Rig tools to provide real-time observability
2
3use anyhow::Result;
4use rig::completion::ToolDefinition;
5use rig::tool::Tool;
6use serde::{Deserialize, Serialize};
7use std::fmt::Debug;
8use std::marker::PhantomData;
9
10use crate::agents::debug;
11
12/// Wrapper that adds debug logging to any Rig tool
13pub struct DebugTool<T>
14where
15    T: Tool,
16{
17    inner: T,
18    _phantom: PhantomData<T>,
19}
20
21impl<T> DebugTool<T>
22where
23    T: Tool,
24{
25    pub fn new(tool: T) -> Self {
26        Self {
27            inner: tool,
28            _phantom: PhantomData,
29        }
30    }
31}
32
33impl<T> Clone for DebugTool<T>
34where
35    T: Tool + Clone,
36{
37    fn clone(&self) -> Self {
38        Self {
39            inner: self.inner.clone(),
40            _phantom: PhantomData,
41        }
42    }
43}
44
45impl<T> Debug for DebugTool<T>
46where
47    T: Tool + Debug,
48{
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        f.debug_struct("DebugTool")
51            .field("inner", &self.inner)
52            .finish()
53    }
54}
55
56impl<T> Serialize for DebugTool<T>
57where
58    T: Tool + Serialize,
59{
60    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
61    where
62        S: serde::Serializer,
63    {
64        self.inner.serialize(serializer)
65    }
66}
67
68impl<'de, T> Deserialize<'de> for DebugTool<T>
69where
70    T: Tool + Deserialize<'de>,
71{
72    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
73    where
74        D: serde::Deserializer<'de>,
75    {
76        let inner = T::deserialize(deserializer)?;
77        Ok(Self {
78            inner,
79            _phantom: PhantomData,
80        })
81    }
82}
83
84impl<T> Tool for DebugTool<T>
85where
86    T: Tool + Send + Sync,
87    T::Args: Debug + Send + Sync,
88    T::Output: Debug + Send + Sync,
89    T::Error: Send + Sync,
90{
91    const NAME: &'static str = T::NAME;
92    type Error = T::Error;
93    type Args = T::Args;
94    type Output = T::Output;
95
96    async fn definition(&self, prompt: String) -> ToolDefinition {
97        self.inner.definition(prompt).await
98    }
99
100    async fn call(&self, args: Self::Args) -> Result<Self::Output, Self::Error> {
101        // Debug output before tool execution
102        let args_str = format!("{:?}", args);
103        debug::debug_tool_call(Self::NAME, &args_str);
104
105        // Start timer
106        let timer = debug::DebugTimer::start(&format!("Tool: {}", Self::NAME));
107
108        // Call the actual tool
109        let result = self.inner.call(args).await;
110
111        // Finish timer
112        timer.finish();
113
114        // Debug output after tool execution
115        match &result {
116            Ok(output) => {
117                let output_str = format!("{:?}", output);
118                debug::debug_tool_response(
119                    Self::NAME,
120                    &output_str,
121                    std::time::Duration::from_secs(0), // Timer already printed
122                );
123            }
124            Err(e) => {
125                debug::debug_error(&format!("Tool {} failed: {:?}", Self::NAME, e));
126            }
127        }
128
129        result
130    }
131}