diff --git a/src/app/(app)/code-reviews/ReviewAgentPageClient.tsx b/src/app/(app)/code-reviews/ReviewAgentPageClient.tsx index fea58a074..af2a6e3f6 100644 --- a/src/app/(app)/code-reviews/ReviewAgentPageClient.tsx +++ b/src/app/(app)/code-reviews/ReviewAgentPageClient.tsx @@ -256,7 +256,7 @@ export function ReviewAgentPageClient({ No Jobs Yet - Connect GitLab and configure your review settings to see code review jobs here. + Connect GitLab and configure your review settings to see processed reviews here. )} diff --git a/src/app/(app)/organizations/[id]/code-reviews/ReviewAgentPageClient.tsx b/src/app/(app)/organizations/[id]/code-reviews/ReviewAgentPageClient.tsx index 22afa5392..fc8bf6470 100644 --- a/src/app/(app)/organizations/[id]/code-reviews/ReviewAgentPageClient.tsx +++ b/src/app/(app)/organizations/[id]/code-reviews/ReviewAgentPageClient.tsx @@ -264,7 +264,7 @@ export function ReviewAgentPageClient({ No Jobs Yet - Connect GitLab and configure your review settings to see code review jobs here. + Connect GitLab and configure your review settings to see processed reviews here. )} diff --git a/src/components/code-reviews/CodeReviewJobsCard.tsx b/src/components/code-reviews/CodeReviewJobsCard.tsx index bbaac7588..e4df7f55d 100644 --- a/src/components/code-reviews/CodeReviewJobsCard.tsx +++ b/src/components/code-reviews/CodeReviewJobsCard.tsx @@ -18,6 +18,8 @@ import { ChevronRight, RotateCcw, Ban, + DollarSign, + Cpu, } from 'lucide-react'; import { toast } from 'sonner'; import { useTRPC } from '@/lib/trpc/utils'; @@ -25,6 +27,20 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { formatDistanceToNow } from 'date-fns'; import { CodeReviewStreamView } from './CodeReviewStreamView'; +function formatCostFromMicrodollars(microdollars: number): string { + const dollars = microdollars / 1_000_000; + if (dollars < 0.01) { + return '<$0.01'; + } + return `$${dollars.toFixed(2)}`; +} + +function formatModelName(model: string): string { + // Strip provider prefix (e.g. "anthropic/claude-sonnet-4-20250514" -> "claude-sonnet-4-20250514") + const lastSlash = model.lastIndexOf('/'); + return lastSlash >= 0 ? model.slice(lastSlash + 1) : model; +} + type Platform = 'github' | 'gitlab'; type CodeReviewJobsCardProps = { @@ -159,7 +175,7 @@ export function CodeReviewJobsCard({ return ( - Code Review Jobs + Processed Reviews Loading... @@ -180,13 +196,13 @@ export function CodeReviewJobsCard({ - Code Review Jobs + Processed Reviews No code reviews yet - Code review jobs will appear here when {prLabel} are reviewed. + Processed reviews will appear here when {prLabel} are reviewed. @@ -198,7 +214,7 @@ export function CodeReviewJobsCard({ - Code Review Jobs + Processed Reviews {total > 0 ? ( @@ -293,6 +309,24 @@ export function CodeReviewJobsCard({ )} + {/* Cost & Model */} + {(review.total_cost_microdollars != null || review.model) && ( + + {review.total_cost_microdollars != null && ( + + + {formatCostFromMicrodollars(review.total_cost_microdollars)} + + )} + {review.model && ( + + + {formatModelName(review.model)} + + )} + + )} + {/* Error Message */} {review.error_message && ( diff --git a/src/lib/code-reviews/core/schemas.ts b/src/lib/code-reviews/core/schemas.ts index 816b30ce8..1a152c1d0 100644 --- a/src/lib/code-reviews/core/schemas.ts +++ b/src/lib/code-reviews/core/schemas.ts @@ -6,7 +6,7 @@ */ import * as z from 'zod'; -import type { CloudAgentCodeReview } from '@/db/schema'; +import type { CodeReviewWithCostAndModel } from '@/lib/code-reviews/db/code-reviews'; import { CodeReviewAgentConfigSchema } from '@/lib/agent-config/core/types'; // ============================================================================ @@ -236,7 +236,7 @@ export type TriggerReviewParams = z.infer; * Response type for list code reviews */ export type ListCodeReviewsResponse = { - reviews: CloudAgentCodeReview[]; + reviews: CodeReviewWithCostAndModel[]; total: number; hasMore: boolean; }; diff --git a/src/lib/code-reviews/db/code-reviews.ts b/src/lib/code-reviews/db/code-reviews.ts index 16870397d..59f754af3 100644 --- a/src/lib/code-reviews/db/code-reviews.ts +++ b/src/lib/code-reviews/db/code-reviews.ts @@ -6,12 +6,17 @@ */ import { db } from '@/lib/drizzle'; -import { cloud_agent_code_reviews } from '@/db/schema'; -import { eq, and, desc, count, ne, inArray } from 'drizzle-orm'; +import { cloud_agent_code_reviews, cliSessions, microdollar_usage } from '@/db/schema'; +import { eq, and, desc, count, ne, inArray, sql, sum } from 'drizzle-orm'; import { captureException } from '@sentry/nextjs'; import type { CreateReviewParams, CodeReviewStatus, ListReviewsParams, Owner } from '../core'; import type { CloudAgentCodeReview } from '@/db/schema'; +export type CodeReviewWithCostAndModel = CloudAgentCodeReview & { + total_cost_microdollars: number | null; + model: string | null; +}; + /** * Creates a new code review record * Returns the created review ID @@ -137,8 +142,11 @@ export async function updateCodeReviewStatus( * Lists code reviews for an owner (org or user) * Supports filtering by status and repository * Returns reviews sorted by creation date (newest first) + * Includes cost (from microdollar_usage) and model (from cliSessions) when available */ -export async function listCodeReviews(params: ListReviewsParams): Promise { +export async function listCodeReviews( + params: ListReviewsParams +): Promise { try { const { owner, limit = 50, offset = 0, status, repoFullName, platform } = params; @@ -174,9 +182,50 @@ export async function listCodeReviews(params: ListReviewsParams): Promise`${costSubquery.total_cost}::bigint`, + model: cliSessions.last_model, + }) .from(cloud_agent_code_reviews) + .leftJoin(cliSessions, eq(cloud_agent_code_reviews.cli_session_id, cliSessions.session_id)) + .leftJoin( + costSubquery, + sql`${costSubquery.session_id} = ${cloud_agent_code_reviews.cli_session_id}::text` + ) .where(and(...conditions)) .orderBy(desc(cloud_agent_code_reviews.created_at)) .limit(limit)
- Code review jobs will appear here when {prLabel} are reviewed. + Processed reviews will appear here when {prLabel} are reviewed.