Skip to content

Commit fee20f9

Browse files
committed
Agent store: Return aggregated stats AND per version stats so it's accurate on the agent page
1 parent ba5cc8f commit fee20f9

File tree

4 files changed

+148
-5
lines changed

4 files changed

+148
-5
lines changed

web/src/app/api/agents/route.ts

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export async function GET() {
2929
)
3030
.orderBy(sql`${schema.agentConfig.created_at} DESC`)
3131

32-
// Get all-time usage metrics for published agents only (those with publisher_id and agent_name)
32+
// Get aggregated all-time usage metrics across all versions
3333
const usageMetrics = await db
3434
.select({
3535
publisher_id: schema.agentRun.publisher_id,
@@ -51,7 +51,7 @@ export async function GET() {
5151
)
5252
.groupBy(schema.agentRun.publisher_id, schema.agentRun.agent_name)
5353

54-
// Get weekly usage metrics for published agents only
54+
// Get aggregated weekly usage metrics across all versions
5555
const weeklyMetrics = await db
5656
.select({
5757
publisher_id: schema.agentRun.publisher_id,
@@ -70,6 +70,59 @@ export async function GET() {
7070
)
7171
.groupBy(schema.agentRun.publisher_id, schema.agentRun.agent_name)
7272

73+
// Get per-version usage metrics for all-time
74+
const perVersionMetrics = await db
75+
.select({
76+
publisher_id: schema.agentRun.publisher_id,
77+
agent_name: schema.agentRun.agent_name,
78+
agent_version: schema.agentRun.agent_version,
79+
total_invocations: sql<number>`COUNT(*)`,
80+
total_dollars: sql<number>`COALESCE(SUM(${schema.agentRun.total_credits}) / 100.0, 0)`,
81+
avg_cost_per_run: sql<number>`COALESCE(AVG(${schema.agentRun.total_credits}) / 100.0, 0)`,
82+
unique_users: sql<number>`COUNT(DISTINCT ${schema.agentRun.user_id})`,
83+
last_used: sql<Date>`MAX(${schema.agentRun.created_at})`,
84+
})
85+
.from(schema.agentRun)
86+
.where(
87+
and(
88+
eq(schema.agentRun.status, 'completed'),
89+
sql`${schema.agentRun.agent_id} != 'test-agent'`,
90+
sql`${schema.agentRun.publisher_id} IS NOT NULL`,
91+
sql`${schema.agentRun.agent_name} IS NOT NULL`,
92+
sql`${schema.agentRun.agent_version} IS NOT NULL`
93+
)
94+
)
95+
.groupBy(
96+
schema.agentRun.publisher_id,
97+
schema.agentRun.agent_name,
98+
schema.agentRun.agent_version
99+
)
100+
101+
// Get per-version weekly usage metrics
102+
const perVersionWeeklyMetrics = await db
103+
.select({
104+
publisher_id: schema.agentRun.publisher_id,
105+
agent_name: schema.agentRun.agent_name,
106+
agent_version: schema.agentRun.agent_version,
107+
weekly_dollars: sql<number>`COALESCE(SUM(${schema.agentRun.total_credits}) / 100.0, 0)`,
108+
})
109+
.from(schema.agentRun)
110+
.where(
111+
and(
112+
eq(schema.agentRun.status, 'completed'),
113+
gte(schema.agentRun.created_at, oneWeekAgo),
114+
sql`${schema.agentRun.agent_id} != 'test-agent'`,
115+
sql`${schema.agentRun.publisher_id} IS NOT NULL`,
116+
sql`${schema.agentRun.agent_name} IS NOT NULL`,
117+
sql`${schema.agentRun.agent_version} IS NOT NULL`
118+
)
119+
)
120+
.groupBy(
121+
schema.agentRun.publisher_id,
122+
schema.agentRun.agent_name,
123+
schema.agentRun.agent_version
124+
)
125+
73126
// Create weekly metrics map by publisher/agent_name
74127
const weeklyMap = new Map()
75128
weeklyMetrics.forEach((metric) => {
@@ -79,7 +132,7 @@ export async function GET() {
79132
}
80133
})
81134

82-
// Create a map of usage metrics by publisher/agent_name
135+
// Create a map of aggregated usage metrics by publisher/agent_name
83136
const metricsMap = new Map()
84137
usageMetrics.forEach((metric) => {
85138
if (metric.publisher_id && metric.agent_name) {
@@ -95,6 +148,41 @@ export async function GET() {
95148
}
96149
})
97150

151+
// Create per-version weekly metrics map
152+
const perVersionWeeklyMap = new Map()
153+
perVersionWeeklyMetrics.forEach((metric) => {
154+
if (metric.publisher_id && metric.agent_name && metric.agent_version) {
155+
const key = `${metric.publisher_id}/${metric.agent_name}@${metric.agent_version}`
156+
perVersionWeeklyMap.set(key, Number(metric.weekly_dollars))
157+
}
158+
})
159+
160+
// Create per-version metrics map
161+
const perVersionMetricsMap = new Map()
162+
perVersionMetrics.forEach((metric) => {
163+
if (metric.publisher_id && metric.agent_name && metric.agent_version) {
164+
const key = `${metric.publisher_id}/${metric.agent_name}@${metric.agent_version}`
165+
perVersionMetricsMap.set(key, {
166+
weekly_dollars: perVersionWeeklyMap.get(key) || 0,
167+
total_dollars: Number(metric.total_dollars),
168+
total_invocations: Number(metric.total_invocations),
169+
avg_cost_per_run: Number(metric.avg_cost_per_run),
170+
unique_users: Number(metric.unique_users),
171+
last_used: metric.last_used,
172+
})
173+
}
174+
})
175+
176+
// Group per-version metrics by agent
177+
const versionMetricsByAgent = new Map()
178+
perVersionMetricsMap.forEach((metrics, key) => {
179+
const [publisherAgentKey, version] = key.split('@')
180+
if (!versionMetricsByAgent.has(publisherAgentKey)) {
181+
versionMetricsByAgent.set(publisherAgentKey, {})
182+
}
183+
versionMetricsByAgent.get(publisherAgentKey)[version] = metrics
184+
})
185+
98186
// First, group agents by publisher/name to get the latest version of each
99187
const latestAgents = new Map()
100188
agents.forEach((agent) => {
@@ -125,19 +213,26 @@ export async function GET() {
125213
last_used: null,
126214
}
127215

216+
// Use agent.id (config ID) to get version stats since that's what the runs table uses as agent_name
217+
const versionStatsKey = `${agent.publisher.id}/${agent.id}`
218+
const version_stats = versionMetricsByAgent.get(versionStatsKey) || {}
219+
128220
return {
129221
id: agent.id,
130222
name: agentName,
131223
description: agentData.description,
132224
publisher: agent.publisher,
133225
version: agent.version,
134226
created_at: agent.created_at,
227+
// Aggregated stats across all versions (for agent store)
135228
usage_count: metrics.total_invocations,
136229
weekly_spent: metrics.weekly_dollars,
137230
total_spent: metrics.total_dollars,
138231
avg_cost_per_invocation: metrics.avg_cost_per_run,
139232
unique_users: metrics.unique_users,
140233
last_used: metrics.last_used,
234+
// Per-version stats for agent detail pages
235+
version_stats,
141236
tags: agentData.tags || [],
142237
}
143238
}

web/src/app/publishers/[id]/agents/[agentId]/[version]/agent-usage-metrics.tsx

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Skeleton } from '@/components/ui/skeleton'
88
interface AgentUsageMetricsProps {
99
publisherId: string
1010
agentId: string
11+
version?: string
1112
}
1213

1314
interface AgentData {
@@ -20,6 +21,17 @@ interface AgentData {
2021
avg_cost_per_invocation?: number
2122
unique_users?: number
2223
last_used?: string
24+
version_stats?: Record<
25+
string,
26+
{
27+
weekly_dollars: number
28+
total_dollars: number
29+
total_invocations: number
30+
avg_cost_per_run: number
31+
unique_users: number
32+
last_used?: Date
33+
}
34+
>
2335
}
2436

2537
const formatCurrency = (amount?: number) => {
@@ -38,6 +50,7 @@ const formatUsageCount = (count?: number) => {
3850
export const AgentUsageMetrics = ({
3951
publisherId,
4052
agentId,
53+
version,
4154
}: AgentUsageMetricsProps) => {
4255
const { data: agents, isLoading } = useQuery<AgentData[]>({
4356
queryKey: ['agents'],
@@ -50,10 +63,30 @@ export const AgentUsageMetrics = ({
5063
},
5164
})
5265

53-
const usageMetrics = agents?.find(
66+
const agent = agents?.find(
5467
(agent) => agent.id === agentId && agent.publisher.id === publisherId
5568
)
5669

70+
// Use version-specific stats if version is provided and exists, otherwise use zero stats
71+
const usageMetrics = version
72+
? agent?.version_stats?.[version]
73+
? {
74+
weekly_spent: agent.version_stats[version].weekly_dollars,
75+
usage_count: agent.version_stats[version].total_invocations,
76+
avg_cost_per_invocation:
77+
agent.version_stats[version].avg_cost_per_run,
78+
unique_users: agent.version_stats[version].unique_users,
79+
last_used: agent.version_stats[version].last_used?.toString(),
80+
}
81+
: {
82+
weekly_spent: 0,
83+
usage_count: 0,
84+
avg_cost_per_invocation: 0,
85+
unique_users: 0,
86+
last_used: undefined,
87+
}
88+
: agent
89+
5790
if (isLoading) {
5891
return (
5992
<Card className="mb-6">

web/src/app/publishers/[id]/agents/[agentId]/[version]/page.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,11 @@ const AgentDetailPage = async ({ params }: AgentDetailPageProps) => {
189189
</Card>
190190

191191
{/* Usage Metrics */}
192-
<AgentUsageMetrics publisherId={params.id} agentId={params.agentId} />
192+
<AgentUsageMetrics
193+
publisherId={params.id}
194+
agentId={params.agentId}
195+
version={params.version}
196+
/>
193197

194198
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
195199
{/* Version Navigation */}

web/src/app/store/page.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ interface AgentData {
4545
avg_cost_per_invocation?: number // In dollars
4646
unique_users?: number
4747
last_used?: string
48+
version_stats?: Record<
49+
string,
50+
{
51+
weekly_dollars: number
52+
total_dollars: number
53+
total_invocations: number
54+
avg_cost_per_run: number
55+
unique_users: number
56+
last_used?: Date
57+
}
58+
>
4859
tags?: string[]
4960
}
5061

0 commit comments

Comments
 (0)