@@ -119,6 +119,26 @@ fn query_messages(conn: &Connection) -> Result<Vec<PiebaldMessage>> {
119119 Ok ( messages)
120120}
121121
122+ /// Query tool call counts per message.
123+ ///
124+ /// Joins `message_parts` → `message_part_tool_call` to count how many tool calls
125+ /// each message made. Returns a map from message ID to tool call count.
126+ fn query_tool_call_counts ( conn : & Connection ) -> Result < HashMap < i64 , u32 > > {
127+ let mut stmt = conn. prepare (
128+ "SELECT mp.parent_chat_message_id, COUNT(*) as tool_call_count
129+ FROM message_parts mp
130+ JOIN message_part_tool_call tc ON tc.message_part_id = mp.id
131+ GROUP BY mp.parent_chat_message_id" ,
132+ ) ?;
133+
134+ let counts = stmt
135+ . query_map ( [ ] , |row| Ok ( ( row. get :: < _ , i64 > ( 0 ) ?, row. get :: < _ , u32 > ( 1 ) ?) ) ) ?
136+ . filter_map ( |r| r. ok ( ) )
137+ . collect ( ) ;
138+
139+ Ok ( counts)
140+ }
141+
122142/// Parse a timestamp string from Piebald's database.
123143///
124144/// Piebald stores timestamps in RFC3339 format with timezone (e.g., "2025-12-10T15:55:48.819321712+00:00").
@@ -134,6 +154,7 @@ fn parse_timestamp(ts: &str) -> Option<DateTime<Utc>> {
134154fn convert_messages (
135155 chats : & [ PiebaldChat ] ,
136156 messages : Vec < PiebaldMessage > ,
157+ tool_call_counts : & HashMap < i64 , u32 > ,
137158) -> Vec < ConversationMessage > {
138159 // Build chat lookup map for O(1) access
139160 let chat_map: HashMap < i64 , & PiebaldChat > = chats. iter ( ) . map ( |c| ( c. id , c) ) . collect ( ) ;
@@ -194,6 +215,9 @@ fn convert_messages(
194215 0.0
195216 } ;
196217
218+ // Look up tool call count for this message
219+ let tool_calls = tool_call_counts. get ( & msg. id ) . copied ( ) . unwrap_or ( 0 ) ;
220+
197221 let stats = Stats {
198222 input_tokens,
199223 output_tokens,
@@ -202,6 +226,7 @@ fn convert_messages(
202226 cache_read_tokens,
203227 cached_tokens : cache_read_tokens + cache_creation_tokens,
204228 cost,
229+ tool_calls,
205230 ..Default :: default ( )
206231 } ;
207232
@@ -251,7 +276,8 @@ impl Analyzer for PiebaldAnalyzer {
251276 let conn = open_piebald_db ( & source. path ) ?;
252277 let chats = query_chats ( & conn) ?;
253278 let messages = query_messages ( & conn) ?;
254- Ok ( convert_messages ( & chats, messages) )
279+ let tool_call_counts = query_tool_call_counts ( & conn) ?;
280+ Ok ( convert_messages ( & chats, messages, & tool_call_counts) )
255281 }
256282
257283 fn parse_sources_parallel ( & self , sources : & [ DataSource ] ) -> Vec < ConversationMessage > {
0 commit comments