systemprompt_analytics/repository/agents/
list_queries.rs1use anyhow::Result;
2use chrono::{DateTime, Utc};
3
4use super::AgentAnalyticsRepository;
5use crate::models::cli::AgentListRow;
6
7impl AgentAnalyticsRepository {
8 pub async fn list_agents(
9 &self,
10 start: DateTime<Utc>,
11 end: DateTime<Utc>,
12 limit: i64,
13 sort_order: &str,
14 ) -> Result<Vec<AgentListRow>> {
15 match sort_order {
16 "success_rate" => self.list_by_success_rate(start, end, limit).await,
17 "cost" => self.list_by_cost(start, end, limit).await,
18 "last_active" => self.list_by_last_active(start, end, limit).await,
19 _ => self.list_by_task_count(start, end, limit).await,
20 }
21 }
22
23 async fn list_by_success_rate(
24 &self,
25 start: DateTime<Utc>,
26 end: DateTime<Utc>,
27 limit: i64,
28 ) -> Result<Vec<AgentListRow>> {
29 sqlx::query_as!(
30 AgentListRow,
31 r#"
32 SELECT
33 t.agent_name as "agent_name!",
34 COUNT(*)::bigint as "task_count!",
35 COUNT(*) FILTER (WHERE t.status = 'completed')::bigint as "completed_count!",
36 COALESCE(AVG(t.execution_time_ms), 0)::bigint as "avg_execution_time_ms!",
37 COALESCE(SUM(r.cost_cents), 0)::bigint as "total_cost_cents!",
38 MAX(t.started_at) as "last_active!"
39 FROM agent_tasks t
40 LEFT JOIN ai_requests r ON r.task_id = t.task_id
41 WHERE t.started_at >= $1 AND t.started_at < $2
42 AND t.agent_name IS NOT NULL
43 GROUP BY t.agent_name
44 ORDER BY CASE WHEN COUNT(*) > 0
45 THEN COUNT(*) FILTER (WHERE t.status = 'completed')::float / COUNT(*)::float
46 ELSE 0 END DESC
47 LIMIT $3
48 "#,
49 start,
50 end,
51 limit
52 )
53 .fetch_all(&*self.pool)
54 .await
55 .map_err(Into::into)
56 }
57
58 async fn list_by_cost(
59 &self,
60 start: DateTime<Utc>,
61 end: DateTime<Utc>,
62 limit: i64,
63 ) -> Result<Vec<AgentListRow>> {
64 sqlx::query_as!(
65 AgentListRow,
66 r#"
67 SELECT
68 t.agent_name as "agent_name!",
69 COUNT(*)::bigint as "task_count!",
70 COUNT(*) FILTER (WHERE t.status = 'completed')::bigint as "completed_count!",
71 COALESCE(AVG(t.execution_time_ms), 0)::bigint as "avg_execution_time_ms!",
72 COALESCE(SUM(r.cost_cents), 0)::bigint as "total_cost_cents!",
73 MAX(t.started_at) as "last_active!"
74 FROM agent_tasks t
75 LEFT JOIN ai_requests r ON r.task_id = t.task_id
76 WHERE t.started_at >= $1 AND t.started_at < $2
77 AND t.agent_name IS NOT NULL
78 GROUP BY t.agent_name
79 ORDER BY COALESCE(SUM(r.cost_cents), 0) DESC
80 LIMIT $3
81 "#,
82 start,
83 end,
84 limit
85 )
86 .fetch_all(&*self.pool)
87 .await
88 .map_err(Into::into)
89 }
90
91 async fn list_by_last_active(
92 &self,
93 start: DateTime<Utc>,
94 end: DateTime<Utc>,
95 limit: i64,
96 ) -> Result<Vec<AgentListRow>> {
97 sqlx::query_as!(
98 AgentListRow,
99 r#"
100 SELECT
101 t.agent_name as "agent_name!",
102 COUNT(*)::bigint as "task_count!",
103 COUNT(*) FILTER (WHERE t.status = 'completed')::bigint as "completed_count!",
104 COALESCE(AVG(t.execution_time_ms), 0)::bigint as "avg_execution_time_ms!",
105 COALESCE(SUM(r.cost_cents), 0)::bigint as "total_cost_cents!",
106 MAX(t.started_at) as "last_active!"
107 FROM agent_tasks t
108 LEFT JOIN ai_requests r ON r.task_id = t.task_id
109 WHERE t.started_at >= $1 AND t.started_at < $2
110 AND t.agent_name IS NOT NULL
111 GROUP BY t.agent_name
112 ORDER BY MAX(t.started_at) DESC
113 LIMIT $3
114 "#,
115 start,
116 end,
117 limit
118 )
119 .fetch_all(&*self.pool)
120 .await
121 .map_err(Into::into)
122 }
123
124 async fn list_by_task_count(
125 &self,
126 start: DateTime<Utc>,
127 end: DateTime<Utc>,
128 limit: i64,
129 ) -> Result<Vec<AgentListRow>> {
130 sqlx::query_as!(
131 AgentListRow,
132 r#"
133 SELECT
134 t.agent_name as "agent_name!",
135 COUNT(*)::bigint as "task_count!",
136 COUNT(*) FILTER (WHERE t.status = 'completed')::bigint as "completed_count!",
137 COALESCE(AVG(t.execution_time_ms), 0)::bigint as "avg_execution_time_ms!",
138 COALESCE(SUM(r.cost_cents), 0)::bigint as "total_cost_cents!",
139 MAX(t.started_at) as "last_active!"
140 FROM agent_tasks t
141 LEFT JOIN ai_requests r ON r.task_id = t.task_id
142 WHERE t.started_at >= $1 AND t.started_at < $2
143 AND t.agent_name IS NOT NULL
144 GROUP BY t.agent_name
145 ORDER BY COUNT(*) DESC
146 LIMIT $3
147 "#,
148 start,
149 end,
150 limit
151 )
152 .fetch_all(&*self.pool)
153 .await
154 .map_err(Into::into)
155 }
156}