diff --git a/app-server/src/api/v1/evaluations.rs b/app-server/src/api/v1/evaluations.rs index a8f0d030..04409684 100644 --- a/app-server/src/api/v1/evaluations.rs +++ b/app-server/src/api/v1/evaluations.rs @@ -1,15 +1,10 @@ use actix_web::{post, web, HttpResponse}; -use chrono::Utc; use serde::Deserialize; use std::sync::Arc; -use uuid::Uuid; use crate::{ - ch::evaluation_scores::{insert_evaluation_scores, EvaluationScore}, db::{self, project_api_keys::ProjectApiKey, DB}, - evaluations::utils::{ - datapoints_to_labeling_queues, get_columns_from_points, EvaluationDatapointResult, - }, + evaluations::{save_evaluation_scores, utils::EvaluationDatapointResult}, names::NameGenerator, routes::types::ResponseResult, }; @@ -52,51 +47,15 @@ async fn create_evaluation( let evaluation = db::evaluations::create_evaluation(&db.pool, &name, project_id, &group_id).await?; - let columns = get_columns_from_points(&points); - let ids = points.iter().map(|_| Uuid::new_v4()).collect::>(); - let labeling_queues = - datapoints_to_labeling_queues(db.clone(), &points, &ids, &project_id).await?; - - for (queue_id, entries) in labeling_queues.iter() { - db::labeling_queues::push_to_labeling_queue(&db.pool, queue_id, &entries).await?; - } - - let ids_clone = ids.clone(); - let db_task = tokio::spawn(async move { - db::evaluations::set_evaluation_results( - db.clone(), - evaluation.id, - &ids_clone, - &columns.scores, - &columns.datas, - &columns.targets, - &columns.executor_outputs, - &columns.trace_ids, - ) - .await - }); - - // Flattened scores from all evaluators to be recorded to Clickhouse - // Its length can be longer than the amount of evaluation datapoints - // since each datapoint can have multiple evaluators - let ch_evaluation_scores = EvaluationScore::from_evaluation_datapoint_results( - &points, - &ids, - project_id, - group_id, + save_evaluation_scores( + db.clone(), + clickhouse, + points, evaluation.id, - Utc::now(), - ); - - let ch_task = tokio::spawn(insert_evaluation_scores( - clickhouse.clone(), - ch_evaluation_scores, - )); - - let (db_result, ch_result) = tokio::join!(db_task, ch_task); - - db_result.map_err(|e| anyhow::anyhow!("Database task failed: {}", e))??; - ch_result.map_err(|e| anyhow::anyhow!("Clickhouse task failed: {}", e))??; + project_id, + &group_id, + ) + .await?; Ok(HttpResponse::Ok().json(evaluation)) } diff --git a/app-server/src/ch/evaluation_scores.rs b/app-server/src/ch/evaluation_scores.rs index 602fab23..64b2ab83 100644 --- a/app-server/src/ch/evaluation_scores.rs +++ b/app-server/src/ch/evaluation_scores.rs @@ -276,3 +276,26 @@ WHERE project_id = ? Ok(row) } + +pub async fn delete_evaluation_score( + clickhouse: clickhouse::Client, + project_id: Uuid, + result_id: Uuid, + label_id: Uuid, +) -> Result<()> { + if !is_feature_enabled(Feature::FullBuild) { + return Ok(()); + } + // Note, this does not immediately physically delete the data. + // https://clickhouse.com/docs/en/sql-reference/statements/delete + clickhouse + .query( + "DELETE FROM evaluation_scores WHERE project_id = ? AND result_id = ? AND label_id = ?", + ) + .bind(project_id) + .bind(result_id) + .bind(label_id) + .execute() + .await?; + Ok(()) +} diff --git a/app-server/src/db/evaluations.rs b/app-server/src/db/evaluations.rs index 4c3e4b9c..874c1ef8 100644 --- a/app-server/src/db/evaluations.rs +++ b/app-server/src/db/evaluations.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, sync::Arc}; +use std::collections::HashMap; use anyhow::Result; use chrono::{DateTime, Utc}; @@ -7,8 +7,6 @@ use serde_json::Value; use sqlx::{prelude::FromRow, PgPool}; use uuid::Uuid; -use super::DB; - #[derive(Serialize, FromRow)] #[serde(rename_all = "camelCase")] pub struct Evaluation { @@ -69,62 +67,11 @@ pub async fn create_evaluation( Ok(evaluation) } -pub async fn get_evaluation( - db: Arc, - project_id: Uuid, - evaluation_id: Uuid, -) -> Result { - let evaluation = sqlx::query_as::<_, Evaluation>( - "SELECT - id, name, project_id, created_at, group_id - FROM evaluations WHERE id = $1 AND project_id = $2", - ) - .bind(evaluation_id) - .bind(project_id) - .fetch_one(&db.pool) - .await?; - - Ok(evaluation) -} - -pub async fn get_evaluations(pool: &PgPool, project_id: Uuid) -> Result> { - let evaluations = sqlx::query_as::<_, Evaluation>( - "SELECT id, name, project_id, created_at, group_id - FROM evaluations WHERE project_id = $1 - ORDER BY created_at DESC", - ) - .bind(project_id) - .fetch_all(pool) - .await?; - - Ok(evaluations) -} - -pub async fn get_evaluations_grouped_by_current_evaluation( - pool: &PgPool, - project_id: Uuid, - current_evaluation_id: Uuid, -) -> Result> { - let evaluations = sqlx::query_as::<_, Evaluation>( - "SELECT id, name, project_id, created_at, group_id - FROM evaluations - WHERE project_id = $1 - AND group_id = (SELECT group_id FROM evaluations WHERE id = $2) - ORDER BY created_at DESC", - ) - .bind(project_id) - .bind(current_evaluation_id) - .fetch_all(pool) - .await?; - - Ok(evaluations) -} - /// Record evaluation results in the database. /// /// Each target may contain an empty JSON object, if there is no target. pub async fn set_evaluation_results( - db: Arc, + pool: &PgPool, evaluation_id: Uuid, ids: &Vec, scores: &Vec>, @@ -164,7 +111,7 @@ pub async fn set_evaluation_results( .bind(trace_ids) .bind(&Vec::from_iter(0..ids.len() as i64)) .bind(evaluation_id) - .fetch_all(&db.pool) + .fetch_all(pool) .await?; // Each datapoint can have multiple scores, so unzip the scores and result ids. @@ -191,49 +138,72 @@ pub async fn set_evaluation_results( .bind(&score_result_ids) .bind(&score_names) .bind(&score_values) - .execute(&db.pool) + .execute(pool) .await?; Ok(()) } -pub async fn get_evaluation_results( +pub async fn add_evaluation_score( pool: &PgPool, - evaluation_id: Uuid, -) -> Result> { - let results = sqlx::query_as::<_, EvaluationDatapoint>( - "WITH scores AS ( - SELECT - result_id, - jsonb_object_agg(name, score) as scores - FROM evaluation_scores - GROUP BY result_id - ) - SELECT - r.id, - r.created_at, - r.evaluation_id, - r.data, - r.target, - r.executor_output, - s.scores, - r.trace_id - FROM evaluation_results r - LEFT JOIN scores s ON r.id = s.result_id - WHERE evaluation_id = $1 - ORDER BY created_at ASC, index_in_batch ASC NULLS FIRST", + result_id: Uuid, + name: &String, + score: f64, + label_id: Option, +) -> Result<()> { + sqlx::query( + "INSERT INTO evaluation_scores (result_id, name, score, label_id) + VALUES ($1, $2, $3, $4)", ) - .bind(evaluation_id) - .fetch_all(pool) + .bind(result_id) + .bind(name) + .bind(score) + .bind(label_id) + .execute(pool) .await?; - Ok(results) + Ok(()) } -pub async fn delete_evaluation(pool: &PgPool, evaluation_id: &Uuid) -> Result<()> { - sqlx::query("DELETE FROM evaluations WHERE id = $1") - .bind(evaluation_id) - .execute(pool) - .await?; +pub async fn get_evaluation_by_result_id( + pool: &PgPool, + project_id: Uuid, + result_id: Uuid, +) -> Result { + let evaluation = sqlx::query_as::<_, Evaluation>( + "SELECT id, created_at, name, project_id, group_id + FROM evaluations + WHERE id = (SELECT evaluation_id FROM evaluation_results WHERE id = $1 LIMIT 1) + AND project_id = $2", + ) + .bind(result_id) + .bind(project_id) + .fetch_one(pool) + .await?; + + Ok(evaluation) +} + +pub async fn delete_evaluation_score( + pool: &PgPool, + project_id: Uuid, + result_id: Uuid, + label_id: Uuid, +) -> Result<()> { + sqlx::query( + "DELETE FROM evaluation_scores + WHERE result_id = $1 AND label_id = $2 + AND result_id IN ( + SELECT id FROM evaluation_results WHERE evaluation_id IN ( + SELECT id from evaluations WHERE project_id = $3 + ) + )", + ) + .bind(result_id) + .bind(label_id) + .bind(project_id) + .execute(pool) + .await?; + Ok(()) } diff --git a/app-server/src/db/labels.rs b/app-server/src/db/labels.rs index 93f09569..0f7631ae 100644 --- a/app-server/src/db/labels.rs +++ b/app-server/src/db/labels.rs @@ -199,7 +199,7 @@ pub async fn update_span_label( VALUES ($1, $2, $3, $4, $5, now(), $6, $7) ON CONFLICT (span_id, class_id, user_id) DO UPDATE SET value = $5, updated_at = now(), label_source = $6, - reasoning = CASE WHEN $7 IS NOT NULL THEN $7 ELSE labels.reasoning END + reasoning = COALESCE($7, labels.reasoning) RETURNING id, span_id, diff --git a/app-server/src/evaluations/mod.rs b/app-server/src/evaluations/mod.rs index b5614dd8..76e0065b 100644 --- a/app-server/src/evaluations/mod.rs +++ b/app-server/src/evaluations/mod.rs @@ -1 +1,110 @@ +use std::sync::Arc; + +use anyhow::Result; +use chrono::Utc; +use uuid::Uuid; + +use crate::{ + ch::evaluation_scores::{insert_evaluation_scores, EvaluationScore}, + db::{self, DB}, +}; +use utils::{datapoints_to_labeling_queues, get_columns_from_points, EvaluationDatapointResult}; + pub mod utils; + +pub async fn save_evaluation_scores( + db: Arc, + clickhouse: clickhouse::Client, + points: Vec, + evaluation_id: Uuid, + project_id: Uuid, + group_id: &String, +) -> Result<()> { + let columns = get_columns_from_points(&points); + let ids = points.iter().map(|_| Uuid::new_v4()).collect::>(); + let labeling_queues = + datapoints_to_labeling_queues(db.clone(), &points, &ids, &project_id).await?; + + for (queue_id, entries) in labeling_queues.iter() { + db::labeling_queues::push_to_labeling_queue(&db.pool, queue_id, &entries).await?; + } + + let pool = db.pool.clone(); + let ids_clone = ids.clone(); + let db_task = tokio::spawn(async move { + db::evaluations::set_evaluation_results( + &pool, + evaluation_id, + &ids_clone, + &columns.scores, + &columns.datas, + &columns.targets, + &columns.executor_outputs, + &columns.trace_ids, + ) + .await + }); + + // Flattened scores from all evaluators to be recorded to Clickhouse + // Its length can be longer than the amount of evaluation datapoints + // since each datapoint can have multiple evaluators + let ch_evaluation_scores = EvaluationScore::from_evaluation_datapoint_results( + &points, + &ids, + project_id, + group_id.clone(), + evaluation_id, + Utc::now(), + ); + + let ch_task = tokio::spawn(insert_evaluation_scores( + clickhouse.clone(), + ch_evaluation_scores, + )); + + let (db_result, ch_result) = tokio::join!(db_task, ch_task); + + db_result.map_err(|e| anyhow::anyhow!("Database task failed: {}", e))??; + ch_result.map_err(|e| anyhow::anyhow!("Clickhouse task failed: {}", e))??; + + Ok(()) +} + +pub async fn add_evaluation_score_from_label( + db: Arc, + clickhouse: clickhouse::Client, + project_id: Uuid, + label_id: Uuid, + result_id: Uuid, + score: f64, + name: String, +) -> Result<()> { + let evaluation = + db::evaluations::get_evaluation_by_result_id(&db.pool, project_id, result_id).await?; + + let pool = db.pool.clone(); + let name_clone = name.clone(); + let db_task = tokio::spawn(async move { + db::evaluations::add_evaluation_score(&pool, result_id, &name_clone, score, Some(label_id)) + .await + }); + + let ch_score = crate::ch::evaluation_scores::EvaluationScore { + project_id, + group_id: evaluation.group_id, + evaluation_id: evaluation.id, + result_id, + name, + value: score, + timestamp: Utc::now(), + }; + + let ch_task = tokio::spawn(insert_evaluation_scores(clickhouse, vec![ch_score])); + + let (db_result, ch_result) = tokio::join!(db_task, ch_task); + + db_result.map_err(|e| anyhow::anyhow!("Database task failed: {}", e))??; + ch_result.map_err(|e| anyhow::anyhow!("Clickhouse task failed: {}", e))??; + + Ok(()) +} diff --git a/app-server/src/routes/labels.rs b/app-server/src/routes/labels.rs index 163b1307..524fca6e 100644 --- a/app-server/src/routes/labels.rs +++ b/app-server/src/routes/labels.rs @@ -110,6 +110,10 @@ struct UpdateSpanLabelRequest { class_id: Uuid, reasoning: Option, source: LabelSource, + #[serde(default)] + datapoint_id: Option, + #[serde(default)] + score_name: Option, } #[post("spans/{span_id}/labels")] @@ -127,6 +131,8 @@ pub async fn update_span_label( let reasoning = req.reasoning; let source = req.source; let clickhouse = clickhouse.into_inner().as_ref().clone(); + let datapoint_id = req.datapoint_id; + let score_name = req.score_name; // evaluator was triggered from the UI // so the source is AUTO @@ -168,21 +174,56 @@ pub async fn update_span_label( reasoning, ) .await?; + + if let Some(datapoint_id) = datapoint_id { + crate::evaluations::add_evaluation_score_from_label( + db.into_inner(), + clickhouse.clone(), + project_id, + label.id, + datapoint_id, + value, + score_name.unwrap_or_default(), + ) + .await?; + } + Ok(HttpResponse::Ok().json(label)) } +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct DeleteLabelParams { + #[serde(default)] + datapoint_id: Option, +} + #[delete("spans/{span_id}/labels/{label_id}")] pub async fn delete_span_label( path: web::Path<(Uuid, Uuid, Uuid)>, + query: web::Query, db: web::Data, clickhouse: web::Data, ) -> ResponseResult { let (project_id, span_id, label_id) = path.into_inner(); + let query = query.into_inner(); let clickhouse = clickhouse.into_inner().as_ref().clone(); - + let datapoint_id = query.datapoint_id; db::labels::delete_span_label(&db.pool, span_id, label_id).await?; crate::ch::labels::delete_label(clickhouse.clone(), project_id, span_id, label_id).await?; + if let Some(datapoint_id) = datapoint_id { + db::evaluations::delete_evaluation_score(&db.pool, project_id, datapoint_id, label_id) + .await?; + crate::ch::evaluation_scores::delete_evaluation_score( + clickhouse.clone(), + project_id, + datapoint_id, + label_id, + ) + .await?; + } + Ok(HttpResponse::Ok().finish()) } diff --git a/clickhouse/001000-initial.sql b/clickhouse/001000-initial.sql index 59236db6..6781a1e1 100644 --- a/clickhouse/001000-initial.sql +++ b/clickhouse/001000-initial.sql @@ -43,7 +43,8 @@ CREATE TABLE evaluation_scores ( evaluation_id UUID, result_id UUID, name String, - value Float64 + value Float64, + label_id UUID DEFAULT '00000000-0000-0000-0000-000000000000' ) ENGINE = MergeTree() ORDER BY (project_id, group_id, timestamp, evaluation_id, name) SETTINGS index_granularity = 8192 diff --git a/frontend/app/api/projects/[projectId]/queues/[queueId]/remove/route.ts b/frontend/app/api/projects/[projectId]/queues/[queueId]/remove/route.ts index 6b17f8b8..129c372d 100644 --- a/frontend/app/api/projects/[projectId]/queues/[queueId]/remove/route.ts +++ b/frontend/app/api/projects/[projectId]/queues/[queueId]/remove/route.ts @@ -1,16 +1,25 @@ -import { and, eq } from 'drizzle-orm'; -import { datapointToSpan, datasetDatapoints, evaluationResults, evaluations, evaluationScores, labelingQueueItems, labelingQueues, labels, spans } from '@/lib/db/migrations/schema'; +import { and, eq, sql } from 'drizzle-orm'; +import { + datapointToSpan, + datasetDatapoints, + evaluationResults, + evaluations, + evaluationScores, + labelingQueueItems, + labels, + spans +} from '@/lib/db/migrations/schema'; import { Feature, isFeatureEnabled } from '@/lib/features/features'; +import { authOptions } from '@/lib/auth'; import { clickhouseClient } from '@/lib/clickhouse/client'; import { dateToNanoseconds } from '@/lib/clickhouse/utils'; import { db } from '@/lib/db/drizzle'; +import { getServerSession } from 'next-auth'; import { z } from 'zod'; -const NANOS_PER_MILLISECOND = 1_000_000; - const removeQueueItemSchema = z.object({ id: z.string(), spanId: z.string(), @@ -31,6 +40,8 @@ const removeQueueItemSchema = z.object({ // remove an item from the queue export async function POST(request: Request, { params }: { params: { projectId: string; queueId: string } }) { + const session = await getServerSession(authOptions); + const user = session!.user; const body = await request.json(); const result = removeQueueItemSchema.safeParse(body); @@ -50,21 +61,29 @@ export async function POST(request: Request, { params }: { params: { projectId: labelSource: "MANUAL" as const, })); - await db.insert(labels).values(newLabels); + const insertedLabels = await db.insert(labels).values(newLabels).onConflictDoUpdate({ + target: [labels.spanId, labels.classId, labels.userId], + set: { + value: sql`excluded.value`, + labelSource: sql`excluded.label_source`, + reasoning: sql`COALESCE(excluded.reasoning, labels.reasoning)`, + } + }).returning(); if (action.resultId) { - const labelingQueue = await db.query.labelingQueues.findFirst({ - where: eq(labelingQueues.id, params.queueId) - }); - const resultId = action.resultId; + const userName = user.name ? ` (${user.name})` : ''; // create new results in batch - const evaluationValues = addedLabels.map(({ value, labelClass }) => ({ - score: value ?? 0, - name: `${labelClass.name}_${labelingQueue?.name}`, - resultId, - })); + const evaluationValues = insertedLabels.map(({ value, classId, id: labelId }) => { + const labelClass = addedLabels.find(({ labelClass }) => labelClass.id === classId)?.labelClass; + return { + score: value ?? 0, + name: `${labelClass?.name}${userName}`, + resultId, + labelId, + }; + }); await db.insert(evaluationScores).values(evaluationValues); @@ -92,7 +111,8 @@ export async function POST(request: Request, { params }: { params: { projectId: result_id: resultId, name: value.name, value: value.score, - timestamp: dateToNanoseconds(new Date()) + timestamp: dateToNanoseconds(new Date()), + label_id: value.labelId, })) }); } diff --git a/frontend/app/api/projects/[projectId]/spans/[spanId]/labels/[labelId]/route.ts b/frontend/app/api/projects/[projectId]/spans/[spanId]/labels/[labelId]/route.ts index f741601e..bf0d4e78 100644 --- a/frontend/app/api/projects/[projectId]/spans/[spanId]/labels/[labelId]/route.ts +++ b/frontend/app/api/projects/[projectId]/spans/[spanId]/labels/[labelId]/route.ts @@ -1,9 +1,10 @@ import { authOptions } from '@/lib/auth'; import { fetcher } from '@/lib/utils'; import { getServerSession } from 'next-auth'; +import { NextRequest } from 'next/server'; export async function DELETE( - req: Request, + req: NextRequest, { params }: { params: { projectId: string; spanId: string; labelId: string } } ): Promise { const projectId = params.projectId; @@ -14,7 +15,8 @@ export async function DELETE( const user = session!.user; return await fetcher( - `/projects/${projectId}/spans/${spanId}/labels/${labelId}`, + `/projects/${projectId}/spans/${spanId}/labels/${labelId}?` + + req.nextUrl.searchParams.toString(), { method: 'DELETE', headers: { diff --git a/frontend/app/api/projects/[projectId]/spans/[spanId]/labels/route.ts b/frontend/app/api/projects/[projectId]/spans/[spanId]/labels/route.ts index 2c32a524..4ab3588d 100644 --- a/frontend/app/api/projects/[projectId]/spans/[spanId]/labels/route.ts +++ b/frontend/app/api/projects/[projectId]/spans/[spanId]/labels/route.ts @@ -32,6 +32,10 @@ export async function POST( const body = await req.json(); + if (body.scoreName) { + body.scoreName = body.scoreName.trim() + (user.name ? ` (${user.name})` : ''); + } + return await fetcher(`/projects/${projectId}/spans/${spanId}/labels`, { method: 'POST', headers: { diff --git a/frontend/components/dashboard/dashboard.tsx b/frontend/components/dashboard/dashboard.tsx index 18cb3a42..61c5d804 100644 --- a/frontend/components/dashboard/dashboard.tsx +++ b/frontend/components/dashboard/dashboard.tsx @@ -9,7 +9,7 @@ import Header from '../ui/header'; import { useProjectContext } from '@/contexts/project-context'; import { TraceStatChart } from './trace-stat-chart'; import { SpanStatChart } from './span-stat-chart'; -import { SpanMetricGroupBy, SpanMetric } from '@/lib/clickhouse/spans'; +import { SpanMetric, SpanMetricGroupBy } from '@/lib/clickhouse/spans'; import { GroupByInterval } from '@/lib/clickhouse/modifiers'; import { ScrollArea } from '../ui/scroll-area'; import { AggregationFunction } from '@/lib/clickhouse/utils'; diff --git a/frontend/components/dashboard/span-summary-chart.tsx b/frontend/components/dashboard/span-summary-chart.tsx index a3acd676..3de869fb 100644 --- a/frontend/components/dashboard/span-summary-chart.tsx +++ b/frontend/components/dashboard/span-summary-chart.tsx @@ -1,11 +1,11 @@ -import { SpanMetricGroupBy, SpanMetric } from "@/lib/clickhouse/spans"; +import { SpanMetric, SpanMetricGroupBy } from "@/lib/clickhouse/spans"; import { AggregationFunction } from "@/lib/clickhouse/utils"; import { cn, toFixedIfFloat } from "@/lib/utils"; import { useEffect, useMemo, useState } from "react"; import { Skeleton } from "../ui/skeleton"; import { useRouter } from "next/navigation"; import { buildSpansUrl } from "@/lib/traces/utils"; -import { Tooltip, TooltipContent, TooltipTrigger, TooltipProvider } from "../ui/tooltip"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip"; interface SpanSummaryChartProps { title: string; diff --git a/frontend/components/queue/labels.tsx b/frontend/components/queue/labels.tsx index 51e9d56b..6c37d623 100644 --- a/frontend/components/queue/labels.tsx +++ b/frontend/components/queue/labels.tsx @@ -123,18 +123,20 @@ export function Labels({ span, onAddLabel }: LabelsProps) {
- {Object.entries(labelClass.valueMap).map(([key, value], index) => ( - -
{ - onAddLabel(value, labelClass); - }} - className="cursor-pointer hover:bg-secondary-foreground/10 p-1 rounded border px-2" - > - {key} -
-
- ))} + {Object.entries(labelClass.valueMap) + .sort(([, valA], [_, valB]) => valA - valB) + .map(([key, value], index) => ( + +
{ + onAddLabel(value, labelClass); + }} + className="cursor-pointer hover:bg-secondary-foreground/10 p-1 rounded border px-2" + > + {key} +
+
+ ))}
diff --git a/frontend/components/traces/add-label-popover.tsx b/frontend/components/traces/add-label-popover.tsx index cd1974fa..a4b9dcf3 100644 --- a/frontend/components/traces/add-label-popover.tsx +++ b/frontend/components/traces/add-label-popover.tsx @@ -48,6 +48,7 @@ import { renderNodeInput } from '@/lib/flow/utils'; import { Switch } from '../ui/switch'; import { toast } from '@/lib/hooks/use-toast'; import { useProjectContext } from '@/contexts/project-context'; +import { useSearchParams } from 'next/navigation'; import { useState } from 'react'; import useSWR from 'swr'; import { v4 } from 'uuid'; @@ -174,7 +175,7 @@ export function AddLabelPopover({ span }: AddLabelPopoverProps) { Add label - +
{mode === 'list' && ( <> @@ -369,6 +370,7 @@ function AddLabelInstance({ onAddLabel: (value: string) => void; }) { const [isLoading, setIsLoading] = useState(false); + const searchParams = useSearchParams(); const addLabel = async ( value: string, @@ -385,6 +387,18 @@ function AddLabelInstance({ }); return; } + const body = { + classId: labelClass.id, + value: labelClass.valueMap[value], + source, + reasoning, + scoreName: labelClass.name, + datapointId: null + } as Record; + + if (span.attributes['lmnr.span.type'] === 'EXECUTOR') { + body.datapointId = searchParams.get('datapointId'); + } const response = await fetch( `/api/projects/${projectId}/spans/${span.spanId}/labels`, @@ -393,12 +407,7 @@ function AddLabelInstance({ headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - classId: labelClass.id, - value: labelClass.valueMap[value], - source: source, - reasoning: reasoning - }) + body: JSON.stringify(body) } ); @@ -510,18 +519,20 @@ function AddLabelInstance({
- {Object.entries(labelClass.valueMap).map(([key, value], index) => ( - -
{ - addLabel(key, labelClass, LabelSource.MANUAL); - }} - className="cursor-pointer hover:bg-secondary-foreground/10 p-1 rounded border px-2" - > - {key} -
-
- ))} + {Object.entries(labelClass.valueMap) + .sort(([, valA], [_, valB]) => valA - valB) + .map(([key, value], index) => ( + +
{ + addLabel(key, labelClass, LabelSource.MANUAL); + }} + className="cursor-pointer hover:bg-secondary-foreground/10 p-1 rounded border px-2" + > + {key} +
+
+ ))}
{labelClass.evaluatorRunnableGraph && (
diff --git a/frontend/components/traces/span-labels.tsx b/frontend/components/traces/span-labels.tsx index a2905128..1ad77305 100644 --- a/frontend/components/traces/span-labels.tsx +++ b/frontend/components/traces/span-labels.tsx @@ -1,5 +1,6 @@ import { cn, swrFetcher } from '@/lib/utils'; import { Info, X } from 'lucide-react'; +import { Span, SpanLabel } from '@/lib/traces/types'; import { Table, TableBody, TableCell, TableRow } from '../ui/table'; import { Tooltip, @@ -11,20 +12,21 @@ import { import { Button } from '../ui/button'; import { eventEmitter } from '@/lib/event-emitter'; import { Skeleton } from '../ui/skeleton'; -import { SpanLabel } from '@/lib/traces/types'; import { useEffect } from 'react'; import { useProjectContext } from '@/contexts/project-context'; +import { useSearchParams } from 'next/navigation'; import useSWR from 'swr'; interface SpanLabelsProps { - spanId: string; + span: Span; } -export default function SpanLabels({ spanId }: SpanLabelsProps) { +export default function SpanLabels({ span }: SpanLabelsProps) { const { projectId } = useProjectContext(); + const searchParams = new URLSearchParams(useSearchParams().toString()); const { data, isLoading, mutate } = useSWR( - `/api/projects/${projectId}/spans/${spanId}/labels`, + `/api/projects/${projectId}/spans/${span.spanId}/labels`, swrFetcher ); @@ -40,8 +42,12 @@ export default function SpanLabels({ spanId }: SpanLabelsProps) { }, [mutate]); const removeLabel = async (labelId: string) => { + const params = (searchParams.get('datapointId') && span.attributes['lmnr.span.type'] === 'EXECUTOR') + ? `?datapointId=${searchParams.get('datapointId')}` + : ''; + console.log(params); const response = await fetch( - `/api/projects/${projectId}/spans/${spanId}/labels/${labelId}`, + `/api/projects/${projectId}/spans/${span.spanId}/labels/${labelId}` + params, { method: 'DELETE', headers: { diff --git a/frontend/components/traces/span-view-span.tsx b/frontend/components/traces/span-view-span.tsx index 8a1aca14..56873c2e 100644 --- a/frontend/components/traces/span-view-span.tsx +++ b/frontend/components/traces/span-view-span.tsx @@ -17,7 +17,7 @@ export function SpanViewSpan({ span }: SpanViewSpanProps) {
- +
Input
{isChatMessageList(span.input) ? ( diff --git a/frontend/lib/db/migrations/0009_lean_turbo.sql b/frontend/lib/db/migrations/0009_lean_turbo.sql new file mode 100644 index 00000000..fc9eb0a3 --- /dev/null +++ b/frontend/lib/db/migrations/0009_lean_turbo.sql @@ -0,0 +1,3 @@ +ALTER TABLE "workspace_usage" ADD PRIMARY KEY ("workspace_id");--> statement-breakpoint +ALTER TABLE "evaluation_scores" ADD COLUMN "label_id" uuid;--> statement-breakpoint +ALTER TABLE "workspace_usage" ADD CONSTRAINT "user_usage_workspace_id_key" UNIQUE("workspace_id");--> statement-breakpoint diff --git a/frontend/lib/db/migrations/meta/0009_snapshot.json b/frontend/lib/db/migrations/meta/0009_snapshot.json new file mode 100644 index 00000000..4869d078 --- /dev/null +++ b/frontend/lib/db/migrations/meta/0009_snapshot.json @@ -0,0 +1,2898 @@ +{ + "id": "cf70f2bb-cf48-4086-9e5f-89f138e79138", + "prevId": "b742a1a2-1e6d-4118-abf1-d88102fd4f7b", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.api_keys": { + "name": "api_keys", + "schema": "", + "columns": { + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'default'" + } + }, + "indexes": { + "api_keys_user_id_idx": { + "name": "api_keys_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "api_keys_user_id_fkey": { + "name": "api_keys_user_id_fkey", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": { + "Enable insert for authenticated users only": { + "name": "Enable insert for authenticated users only", + "as": "PERMISSIVE", + "for": "ALL", + "to": [ + "service_role" + ], + "using": "true", + "withCheck": "true" + } + }, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.datapoint_to_span": { + "name": "datapoint_to_span", + "schema": "", + "columns": { + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "datapoint_id": { + "name": "datapoint_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "span_id": { + "name": "span_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "datapoint_to_span_datapoint_id_fkey": { + "name": "datapoint_to_span_datapoint_id_fkey", + "tableFrom": "datapoint_to_span", + "tableTo": "dataset_datapoints", + "columnsFrom": [ + "datapoint_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "datapoint_to_span_span_id_project_id_fkey": { + "name": "datapoint_to_span_span_id_project_id_fkey", + "tableFrom": "datapoint_to_span", + "tableTo": "spans", + "columnsFrom": [ + "span_id", + "project_id" + ], + "columnsTo": [ + "span_id", + "project_id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": { + "datapoint_to_span_pkey": { + "name": "datapoint_to_span_pkey", + "columns": [ + "datapoint_id", + "span_id", + "project_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.dataset_datapoints": { + "name": "dataset_datapoints", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "dataset_id": { + "name": "dataset_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "indexed_on": { + "name": "indexed_on", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "target": { + "name": "target", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + }, + "index_in_batch": { + "name": "index_in_batch", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "dataset_datapoints_dataset_id_fkey": { + "name": "dataset_datapoints_dataset_id_fkey", + "tableFrom": "dataset_datapoints", + "tableTo": "datasets", + "columnsFrom": [ + "dataset_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.datasets": { + "name": "datasets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true, + "default": "gen_random_uuid()" + }, + "indexed_on": { + "name": "indexed_on", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "public_datasets_project_id_fkey": { + "name": "public_datasets_project_id_fkey", + "tableFrom": "datasets", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.evaluation_results": { + "name": "evaluation_results", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "evaluation_id": { + "name": "evaluation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "target": { + "name": "target", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "executor_output": { + "name": "executor_output", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "index_in_batch": { + "name": "index_in_batch", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "trace_id": { + "name": "trace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "evaluation_results_evaluation_id_idx": { + "name": "evaluation_results_evaluation_id_idx", + "columns": [ + { + "expression": "evaluation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "evaluation_results_evaluation_id_fkey1": { + "name": "evaluation_results_evaluation_id_fkey1", + "tableFrom": "evaluation_results", + "tableTo": "evaluations", + "columnsFrom": [ + "evaluation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": { + "select_by_next_api_key": { + "name": "select_by_next_api_key", + "as": "PERMISSIVE", + "for": "SELECT", + "to": [ + "anon", + "authenticated" + ], + "using": "is_evaluation_id_accessible_for_api_key(api_key(), evaluation_id)" + } + }, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.evaluation_scores": { + "name": "evaluation_scores", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "result_id": { + "name": "result_id", + "type": "uuid", + "primaryKey": false, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "score": { + "name": "score", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "label_id": { + "name": "label_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "evaluation_scores_result_id_idx": { + "name": "evaluation_scores_result_id_idx", + "columns": [ + { + "expression": "result_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hash", + "with": {} + } + }, + "foreignKeys": { + "evaluation_scores_result_id_fkey": { + "name": "evaluation_scores_result_id_fkey", + "tableFrom": "evaluation_scores", + "tableTo": "evaluation_results", + "columnsFrom": [ + "result_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "evaluation_results_names_unique": { + "name": "evaluation_results_names_unique", + "nullsNotDistinct": false, + "columns": [ + "result_id", + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.evaluations": { + "name": "evaluations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'default'" + } + }, + "indexes": {}, + "foreignKeys": { + "evaluations_project_id_fkey1": { + "name": "evaluations_project_id_fkey1", + "tableFrom": "evaluations", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": { + "select_by_next_api_key": { + "name": "select_by_next_api_key", + "as": "PERMISSIVE", + "for": "SELECT", + "to": [ + "anon", + "authenticated" + ], + "using": "is_evaluation_id_accessible_for_api_key(api_key(), id)" + } + }, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.event_templates": { + "name": "event_templates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "event_type": { + "name": "event_type", + "type": "event_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'BOOLEAN'" + } + }, + "indexes": {}, + "foreignKeys": { + "event_templates_project_id_fkey": { + "name": "event_templates_project_id_fkey", + "tableFrom": "event_templates", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "unique_name_project_id": { + "name": "unique_name_project_id", + "nullsNotDistinct": false, + "columns": [ + "name", + "project_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "span_id": { + "name": "span_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "template_id": { + "name": "template_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "event_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "value": { + "name": "value", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inputs": { + "name": "inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "events_template_id_fkey": { + "name": "events_template_id_fkey", + "tableFrom": "events", + "tableTo": "event_templates", + "columnsFrom": [ + "template_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.label_classes": { + "name": "label_classes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "label_type": { + "name": "label_type", + "type": "label_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "value_map": { + "name": "value_map", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[false,true]'::jsonb" + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "evaluator_runnable_graph": { + "name": "evaluator_runnable_graph", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "pipeline_version_id": { + "name": "pipeline_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "label_classes_project_id_fkey": { + "name": "label_classes_project_id_fkey", + "tableFrom": "label_classes", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.label_classes_for_path": { + "name": "label_classes_for_path", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true, + "default": "gen_random_uuid()" + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label_class_id": { + "name": "label_class_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "autoeval_labels_project_id_fkey": { + "name": "autoeval_labels_project_id_fkey", + "tableFrom": "label_classes_for_path", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "unique_project_id_path_label_class": { + "name": "unique_project_id_path_label_class", + "nullsNotDistinct": false, + "columns": [ + "project_id", + "path", + "label_class_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.labeling_queue_items": { + "name": "labeling_queue_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "queue_id": { + "name": "queue_id", + "type": "uuid", + "primaryKey": false, + "notNull": true, + "default": "gen_random_uuid()" + }, + "action": { + "name": "action", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "span_id": { + "name": "span_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "labelling_queue_items_queue_id_fkey": { + "name": "labelling_queue_items_queue_id_fkey", + "tableFrom": "labeling_queue_items", + "tableTo": "labeling_queues", + "columnsFrom": [ + "queue_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.labeling_queues": { + "name": "labeling_queues", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "labeling_queues_project_id_fkey": { + "name": "labeling_queues_project_id_fkey", + "tableFrom": "labeling_queues", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.labels": { + "name": "labels", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "class_id": { + "name": "class_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "double precision", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "span_id": { + "name": "span_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false, + "default": "gen_random_uuid()" + }, + "label_source": { + "name": "label_source", + "type": "label_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'MANUAL'" + }, + "reasoning": { + "name": "reasoning", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "trace_tags_type_id_fkey": { + "name": "trace_tags_type_id_fkey", + "tableFrom": "labels", + "tableTo": "label_classes", + "columnsFrom": [ + "class_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "labels_span_id_class_id_user_id_key": { + "name": "labels_span_id_class_id_user_id_key", + "nullsNotDistinct": false, + "columns": [ + "class_id", + "span_id", + "user_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.llm_prices": { + "name": "llm_prices", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "input_price_per_million": { + "name": "input_price_per_million", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "output_price_per_million": { + "name": "output_price_per_million", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "input_cached_price_per_million": { + "name": "input_cached_price_per_million", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "additional_prices": { + "name": "additional_prices", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.members_of_workspaces": { + "name": "members_of_workspaces", + "schema": "", + "columns": { + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "member_role": { + "name": "member_role", + "type": "workspace_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'owner'" + } + }, + "indexes": { + "members_of_workspaces_user_id_idx": { + "name": "members_of_workspaces_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "members_of_workspaces_user_id_fkey": { + "name": "members_of_workspaces_user_id_fkey", + "tableFrom": "members_of_workspaces", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "public_members_of_workspaces_workspace_id_fkey": { + "name": "public_members_of_workspaces_workspace_id_fkey", + "tableFrom": "members_of_workspaces", + "tableTo": "workspaces", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "members_of_workspaces_user_workspace_unique": { + "name": "members_of_workspaces_user_workspace_unique", + "nullsNotDistinct": false, + "columns": [ + "workspace_id", + "user_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pipeline_templates": { + "name": "pipeline_templates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "runnable_graph": { + "name": "runnable_graph", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "displayable_graph": { + "name": "displayable_graph", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "number_of_nodes": { + "name": "number_of_nodes", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "display_group": { + "name": "display_group", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'build'" + }, + "ordinal": { + "name": "ordinal", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 500 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pipeline_versions": { + "name": "pipeline_versions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "pipeline_id": { + "name": "pipeline_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "displayable_graph": { + "name": "displayable_graph", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "runnable_graph": { + "name": "runnable_graph", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "pipeline_type": { + "name": "pipeline_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": { + "all_actions_by_next_api_key": { + "name": "all_actions_by_next_api_key", + "as": "PERMISSIVE", + "for": "ALL", + "to": [ + "anon", + "authenticated" + ], + "using": "is_pipeline_id_accessible_for_api_key(api_key(), pipeline_id)" + } + }, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pipelines": { + "name": "pipelines", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "visibility": { + "name": "visibility", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'PRIVATE'" + }, + "python_requirements": { + "name": "python_requirements", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": { + "pipelines_name_project_id_idx": { + "name": "pipelines_name_project_id_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pipelines_project_id_idx": { + "name": "pipelines_project_id_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pipelines_project_id_fkey": { + "name": "pipelines_project_id_fkey", + "tableFrom": "pipelines", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "unique_project_id_pipeline_name": { + "name": "unique_project_id_pipeline_name", + "nullsNotDistinct": false, + "columns": [ + "project_id", + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.playgrounds": { + "name": "playgrounds", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "prompt_messages": { + "name": "prompt_messages", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[{\"role\":\"user\",\"content\":\"\"}]'::jsonb" + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "output_schema": { + "name": "output_schema", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "playgrounds_project_id_fkey": { + "name": "playgrounds_project_id_fkey", + "tableFrom": "playgrounds", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_api_keys": { + "name": "project_api_keys", + "schema": "", + "columns": { + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "shorthand": { + "name": "shorthand", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "hash": { + "name": "hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + } + }, + "indexes": {}, + "foreignKeys": { + "public_project_api_keys_project_id_fkey": { + "name": "public_project_api_keys_project_id_fkey", + "tableFrom": "project_api_keys", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.projects": { + "name": "projects", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "projects_workspace_id_idx": { + "name": "projects_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "projects_workspace_id_fkey": { + "name": "projects_workspace_id_fkey", + "tableFrom": "projects", + "tableTo": "workspaces", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.provider_api_keys": { + "name": "provider_api_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true, + "default": "gen_random_uuid()" + }, + "nonce_hex": { + "name": "nonce_hex", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "provider_api_keys_project_id_fkey": { + "name": "provider_api_keys_project_id_fkey", + "tableFrom": "provider_api_keys", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.spans": { + "name": "spans", + "schema": "", + "columns": { + "span_id": { + "name": "span_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "parent_span_id": { + "name": "parent_span_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "attributes": { + "name": "attributes", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "input": { + "name": "input", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "output": { + "name": "output", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "span_type": { + "name": "span_type", + "type": "span_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "start_time": { + "name": "start_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "end_time": { + "name": "end_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "trace_id": { + "name": "trace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "input_preview": { + "name": "input_preview", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "output_preview": { + "name": "output_preview", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "span_path_idx": { + "name": "span_path_idx", + "columns": [ + { + "expression": "(attributes -> 'lmnr.span.path'::text)", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "spans_project_id_idx": { + "name": "spans_project_id_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hash", + "with": {} + }, + "spans_project_id_trace_id_start_time_idx": { + "name": "spans_project_id_trace_id_start_time_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "trace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "start_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "spans_root_project_id_start_time_end_time_trace_id_idx": { + "name": "spans_root_project_id_start_time_end_time_trace_id_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "start_time", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "end_time", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "trace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "(parent_span_id IS NULL)", + "concurrently": false, + "method": "btree", + "with": {} + }, + "spans_start_time_end_time_idx": { + "name": "spans_start_time_end_time_idx", + "columns": [ + { + "expression": "start_time", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "end_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "spans_trace_id_idx": { + "name": "spans_trace_id_idx", + "columns": [ + { + "expression": "trace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "spans_trace_id_start_time_idx": { + "name": "spans_trace_id_start_time_idx", + "columns": [ + { + "expression": "trace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "start_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "new_spans_trace_id_fkey": { + "name": "new_spans_trace_id_fkey", + "tableFrom": "spans", + "tableTo": "traces", + "columnsFrom": [ + "trace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "spans_project_id_fkey": { + "name": "spans_project_id_fkey", + "tableFrom": "spans", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": { + "spans_pkey": { + "name": "spans_pkey", + "columns": [ + "span_id", + "project_id" + ] + } + }, + "uniqueConstraints": { + "unique_span_id_project_id": { + "name": "unique_span_id_project_id", + "nullsNotDistinct": false, + "columns": [ + "span_id", + "project_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.subscription_tiers": { + "name": "subscription_tiers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "primaryKey": true, + "notNull": true, + "identity": { + "type": "byDefault", + "name": "subscription_tiers_id_seq", + "schema": "public", + "increment": "1", + "startWith": "1", + "minValue": "1", + "maxValue": "9223372036854776000", + "cache": "1", + "cycle": false + } + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "storage_mib": { + "name": "storage_mib", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "log_retention_days": { + "name": "log_retention_days", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "members_per_workspace": { + "name": "members_per_workspace", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'-1'" + }, + "num_workspaces": { + "name": "num_workspaces", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'-1'" + }, + "stripe_product_id": { + "name": "stripe_product_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "events": { + "name": "events", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "spans": { + "name": "spans", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "extra_span_price": { + "name": "extra_span_price", + "type": "double precision", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "extra_event_price": { + "name": "extra_event_price", + "type": "double precision", + "primaryKey": false, + "notNull": true, + "default": "'0'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.target_pipeline_versions": { + "name": "target_pipeline_versions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "pipeline_id": { + "name": "pipeline_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "pipeline_version_id": { + "name": "pipeline_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "target_pipeline_versions_pipeline_id_fkey": { + "name": "target_pipeline_versions_pipeline_id_fkey", + "tableFrom": "target_pipeline_versions", + "tableTo": "pipelines", + "columnsFrom": [ + "pipeline_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "target_pipeline_versions_pipeline_version_id_fkey": { + "name": "target_pipeline_versions_pipeline_version_id_fkey", + "tableFrom": "target_pipeline_versions", + "tableTo": "pipeline_versions", + "columnsFrom": [ + "pipeline_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "unique_pipeline_id": { + "name": "unique_pipeline_id", + "nullsNotDistinct": false, + "columns": [ + "pipeline_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.traces": { + "name": "traces", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "end_time": { + "name": "end_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "start_time": { + "name": "start_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "total_token_count": { + "name": "total_token_count", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "cost": { + "name": "cost", + "type": "double precision", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "trace_type": { + "name": "trace_type", + "type": "trace_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'DEFAULT'" + }, + "input_token_count": { + "name": "input_token_count", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "output_token_count": { + "name": "output_token_count", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "input_cost": { + "name": "input_cost", + "type": "double precision", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "output_cost": { + "name": "output_cost", + "type": "double precision", + "primaryKey": false, + "notNull": true, + "default": "'0'" + } + }, + "indexes": { + "trace_metadata_gin_idx": { + "name": "trace_metadata_gin_idx", + "columns": [ + { + "expression": "metadata", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + }, + "traces_id_project_id_start_time_times_not_null_idx": { + "name": "traces_id_project_id_start_time_times_not_null_idx", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "start_time", + "isExpression": false, + "asc": false, + "nulls": "first" + } + ], + "isUnique": false, + "where": "((start_time IS NOT NULL) AND (end_time IS NOT NULL))", + "concurrently": false, + "method": "btree", + "with": {} + }, + "traces_project_id_idx": { + "name": "traces_project_id_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "traces_project_id_trace_type_start_time_end_time_idx": { + "name": "traces_project_id_trace_type_start_time_end_time_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "start_time", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "end_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "((trace_type = 'DEFAULT'::trace_type) AND (start_time IS NOT NULL) AND (end_time IS NOT NULL))", + "concurrently": false, + "method": "btree", + "with": {} + }, + "traces_session_id_idx": { + "name": "traces_session_id_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "traces_start_time_end_time_idx": { + "name": "traces_start_time_end_time_idx", + "columns": [ + { + "expression": "start_time", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "end_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "new_traces_project_id_fkey": { + "name": "new_traces_project_id_fkey", + "tableFrom": "traces", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": { + "select_by_next_api_key": { + "name": "select_by_next_api_key", + "as": "PERMISSIVE", + "for": "SELECT", + "to": [ + "anon", + "authenticated" + ], + "using": "is_trace_id_accessible_for_api_key(api_key(), id)" + } + }, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_subscription_info": { + "name": "user_subscription_info", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "activated": { + "name": "activated", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "user_subscription_info_stripe_customer_id_idx": { + "name": "user_subscription_info_stripe_customer_id_idx", + "columns": [ + { + "expression": "stripe_customer_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_subscription_info_fkey": { + "name": "user_subscription_info_fkey", + "tableFrom": "user_subscription_info", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_key": { + "name": "users_email_key", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": { + "Enable insert for authenticated users only": { + "name": "Enable insert for authenticated users only", + "as": "PERMISSIVE", + "for": "INSERT", + "to": [ + "service_role" + ], + "withCheck": "true" + } + }, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_usage": { + "name": "workspace_usage", + "schema": "", + "columns": { + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "span_count": { + "name": "span_count", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "span_count_since_reset": { + "name": "span_count_since_reset", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "prev_span_count": { + "name": "prev_span_count", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "event_count": { + "name": "event_count", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "event_count_since_reset": { + "name": "event_count_since_reset", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "prev_event_count": { + "name": "prev_event_count", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "reset_time": { + "name": "reset_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "reset_reason": { + "name": "reset_reason", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'signup'" + } + }, + "indexes": {}, + "foreignKeys": { + "user_usage_workspace_id_fkey": { + "name": "user_usage_workspace_id_fkey", + "tableFrom": "workspace_usage", + "tableTo": "workspaces", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_usage_workspace_id_key": { + "name": "user_usage_workspace_id_key", + "nullsNotDistinct": false, + "columns": [ + "workspace_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspaces": { + "name": "workspaces", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tier_id": { + "name": "tier_id", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'1'" + }, + "subscription_id": { + "name": "subscription_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "additional_seats": { + "name": "additional_seats", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": "'0'" + } + }, + "indexes": {}, + "foreignKeys": { + "workspaces_tier_id_fkey": { + "name": "workspaces_tier_id_fkey", + "tableFrom": "workspaces", + "tableTo": "subscription_tiers", + "columnsFrom": [ + "tier_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.event_source": { + "name": "event_source", + "schema": "public", + "values": [ + "AUTO", + "MANUAL", + "CODE" + ] + }, + "public.event_type": { + "name": "event_type", + "schema": "public", + "values": [ + "BOOLEAN", + "STRING", + "NUMBER" + ] + }, + "public.label_source": { + "name": "label_source", + "schema": "public", + "values": [ + "MANUAL", + "AUTO", + "CODE" + ] + }, + "public.label_type": { + "name": "label_type", + "schema": "public", + "values": [ + "BOOLEAN", + "CATEGORICAL" + ] + }, + "public.span_type": { + "name": "span_type", + "schema": "public", + "values": [ + "DEFAULT", + "LLM", + "PIPELINE", + "EXECUTOR", + "EVALUATOR", + "EVALUATION" + ] + }, + "public.trace_type": { + "name": "trace_type", + "schema": "public", + "values": [ + "DEFAULT", + "EVENT", + "EVALUATION" + ] + }, + "public.workspace_role": { + "name": "workspace_role", + "schema": "public", + "values": [ + "member", + "owner" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/frontend/lib/db/migrations/meta/_journal.json b/frontend/lib/db/migrations/meta/_journal.json index ce86fac3..cf9dfd01 100644 --- a/frontend/lib/db/migrations/meta/_journal.json +++ b/frontend/lib/db/migrations/meta/_journal.json @@ -64,6 +64,13 @@ "when": 1731737194366, "tag": "0008_nosy_jean_grey", "breakpoints": true + }, + { + "idx": 9, + "version": "7", + "when": 1732571729998, + "tag": "0009_lean_turbo", + "breakpoints": true } ] } \ No newline at end of file diff --git a/frontend/lib/db/migrations/relations.ts b/frontend/lib/db/migrations/relations.ts index f4f20972..06eb69d7 100644 --- a/frontend/lib/db/migrations/relations.ts +++ b/frontend/lib/db/migrations/relations.ts @@ -1,57 +1,70 @@ -import { apiKeys, datapointToSpan, datasetDatapoints, datasets, evaluationResults, evaluations, evaluationScores, events, eventTemplates, labelClasses, labelClassesForPath, labelingQueueItems, labelingQueues, labels, membersOfWorkspaces, pipelines, pipelineVersions, playgrounds, projectApiKeys, projects, providerApiKeys, spans, subscriptionTiers, targetPipelineVersions, traces, users, userSubscriptionInfo, workspaces,workspaceUsage } from "./schema"; import { relations } from "drizzle-orm/relations"; +import { apiKeys, datapointToSpan, datasetDatapoints, datasets, evaluationResults, evaluations, evaluationScores, events, eventTemplates, labelClasses, labelClassesForPath, labelingQueueItems, labelingQueues, labels, membersOfWorkspaces, pipelines, pipelineVersions, playgrounds, projectApiKeys, projects, providerApiKeys, spans, subscriptionTiers, targetPipelineVersions, traces, users, userSubscriptionInfo, workspaces, workspaceUsage } from "./schema"; -export const datasetsRelations = relations(datasets, ({one, many}) => ({ +export const targetPipelineVersionsRelations = relations(targetPipelineVersions, ({one}) => ({ + pipeline: one(pipelines, { + fields: [targetPipelineVersions.pipelineId], + references: [pipelines.id] + }), + pipelineVersion: one(pipelineVersions, { + fields: [targetPipelineVersions.pipelineVersionId], + references: [pipelineVersions.id] + }), +})); + +export const pipelinesRelations = relations(pipelines, ({one, many}) => ({ + targetPipelineVersions: many(targetPipelineVersions), project: one(projects, { - fields: [datasets.projectId], + fields: [pipelines.projectId], references: [projects.id] }), - datasetDatapoints: many(datasetDatapoints), +})); + +export const pipelineVersionsRelations = relations(pipelineVersions, ({many}) => ({ + targetPipelineVersions: many(targetPipelineVersions), +})); + +export const tracesRelations = relations(traces, ({one, many}) => ({ + project: one(projects, { + fields: [traces.projectId], + references: [projects.id] + }), + spans: many(spans), })); export const projectsRelations = relations(projects, ({one, many}) => ({ + traces: many(traces), + labelingQueues: many(labelingQueues), + providerApiKeys: many(providerApiKeys), + evaluations: many(evaluations), + eventTemplates: many(eventTemplates), + playgrounds: many(playgrounds), + labelClassesForPaths: many(labelClassesForPath), datasets: many(datasets), + pipelines: many(pipelines), workspace: one(workspaces, { fields: [projects.workspaceId], references: [workspaces.id] }), - eventTemplates: many(eventTemplates), - labelClasses: many(labelClasses), - labelClassesForPaths: many(labelClassesForPath), - pipelines: many(pipelines), projectApiKeys: many(projectApiKeys), - providerApiKeys: many(providerApiKeys), - labelingQueues: many(labelingQueues), - traces: many(traces), - evaluations: many(evaluations), - playgrounds: many(playgrounds), + labelClasses: many(labelClasses), spans: many(spans), })); -export const datasetDatapointsRelations = relations(datasetDatapoints, ({one, many}) => ({ - dataset: one(datasets, { - fields: [datasetDatapoints.datasetId], - references: [datasets.id] - }), - datapointToSpans: many(datapointToSpan), -})); - -export const workspacesRelations = relations(workspaces, ({one, many}) => ({ - projects: many(projects), - membersOfWorkspaces: many(membersOfWorkspaces), - subscriptionTier: one(subscriptionTiers, { - fields: [workspaces.tierId], - references: [subscriptionTiers.id] +export const evaluationResultsRelations = relations(evaluationResults, ({one, many}) => ({ + evaluation: one(evaluations, { + fields: [evaluationResults.evaluationId], + references: [evaluations.id] }), - workspaceUsages: many(workspaceUsage), + evaluationScores: many(evaluationScores), })); -export const eventTemplatesRelations = relations(eventTemplates, ({one, many}) => ({ +export const evaluationsRelations = relations(evaluations, ({one, many}) => ({ + evaluationResults: many(evaluationResults), project: one(projects, { - fields: [eventTemplates.projectId], + fields: [evaluations.projectId], references: [projects.id] }), - events: many(events), })); export const eventsRelations = relations(events, ({one}) => ({ @@ -61,128 +74,94 @@ export const eventsRelations = relations(events, ({one}) => ({ }), })); -export const labelClassesRelations = relations(labelClasses, ({one, many}) => ({ +export const eventTemplatesRelations = relations(eventTemplates, ({one, many}) => ({ + events: many(events), project: one(projects, { - fields: [labelClasses.projectId], + fields: [eventTemplates.projectId], references: [projects.id] }), - labels: many(labels), })); -export const labelClassesForPathRelations = relations(labelClassesForPath, ({one}) => ({ +export const labelingQueuesRelations = relations(labelingQueues, ({one, many}) => ({ project: one(projects, { - fields: [labelClassesForPath.projectId], + fields: [labelingQueues.projectId], references: [projects.id] }), + labelingQueueItems: many(labelingQueueItems), })); -export const labelsRelations = relations(labels, ({one}) => ({ - labelClass: one(labelClasses, { - fields: [labels.classId], - references: [labelClasses.id] +export const providerApiKeysRelations = relations(providerApiKeys, ({one}) => ({ + project: one(projects, { + fields: [providerApiKeys.projectId], + references: [projects.id] }), })); -export const membersOfWorkspacesRelations = relations(membersOfWorkspaces, ({one}) => ({ - user: one(users, { - fields: [membersOfWorkspaces.userId], - references: [users.id] - }), +export const workspaceUsageRelations = relations(workspaceUsage, ({one}) => ({ workspace: one(workspaces, { - fields: [membersOfWorkspaces.workspaceId], + fields: [workspaceUsage.workspaceId], references: [workspaces.id] }), })); -export const usersRelations = relations(users, ({many}) => ({ +export const workspacesRelations = relations(workspaces, ({one, many}) => ({ + workspaceUsages: many(workspaceUsage), membersOfWorkspaces: many(membersOfWorkspaces), - apiKeys: many(apiKeys), - userSubscriptionInfos: many(userSubscriptionInfo), -})); - -export const apiKeysRelations = relations(apiKeys, ({one}) => ({ - user: one(users, { - fields: [apiKeys.userId], - references: [users.id] + projects: many(projects), + subscriptionTier: one(subscriptionTiers, { + fields: [workspaces.tierId], + references: [subscriptionTiers.id] }), })); -export const subscriptionTiersRelations = relations(subscriptionTiers, ({many}) => ({ - workspaces: many(workspaces), -})); - -export const pipelinesRelations = relations(pipelines, ({one, many}) => ({ - project: one(projects, { - fields: [pipelines.projectId], - references: [projects.id] +export const evaluationScoresRelations = relations(evaluationScores, ({one}) => ({ + evaluationResult: one(evaluationResults, { + fields: [evaluationScores.resultId], + references: [evaluationResults.id] }), - targetPipelineVersions: many(targetPipelineVersions), })); -export const projectApiKeysRelations = relations(projectApiKeys, ({one}) => ({ +export const playgroundsRelations = relations(playgrounds, ({one}) => ({ project: one(projects, { - fields: [projectApiKeys.projectId], + fields: [playgrounds.projectId], references: [projects.id] }), })); -export const providerApiKeysRelations = relations(providerApiKeys, ({one}) => ({ +export const labelClassesForPathRelations = relations(labelClassesForPath, ({one}) => ({ project: one(projects, { - fields: [providerApiKeys.projectId], + fields: [labelClassesForPath.projectId], references: [projects.id] }), })); -export const targetPipelineVersionsRelations = relations(targetPipelineVersions, ({one}) => ({ - pipeline: one(pipelines, { - fields: [targetPipelineVersions.pipelineId], - references: [pipelines.id] - }), - pipelineVersion: one(pipelineVersions, { - fields: [targetPipelineVersions.pipelineVersionId], - references: [pipelineVersions.id] - }), -})); - -export const pipelineVersionsRelations = relations(pipelineVersions, ({many}) => ({ - targetPipelineVersions: many(targetPipelineVersions), -})); - -export const userSubscriptionInfoRelations = relations(userSubscriptionInfo, ({one}) => ({ +export const apiKeysRelations = relations(apiKeys, ({one}) => ({ user: one(users, { - fields: [userSubscriptionInfo.userId], + fields: [apiKeys.userId], references: [users.id] }), })); -export const workspaceUsageRelations = relations(workspaceUsage, ({one}) => ({ - workspace: one(workspaces, { - fields: [workspaceUsage.workspaceId], - references: [workspaces.id] - }), -})); - -export const evaluationScoresRelations = relations(evaluationScores, ({one}) => ({ - evaluationResult: one(evaluationResults, { - fields: [evaluationScores.resultId], - references: [evaluationResults.id] - }), +export const usersRelations = relations(users, ({many}) => ({ + apiKeys: many(apiKeys), + membersOfWorkspaces: many(membersOfWorkspaces), + userSubscriptionInfos: many(userSubscriptionInfo), })); -export const evaluationResultsRelations = relations(evaluationResults, ({one, many}) => ({ - evaluationScores: many(evaluationScores), - evaluation: one(evaluations, { - fields: [evaluationResults.evaluationId], - references: [evaluations.id] +export const datasetDatapointsRelations = relations(datasetDatapoints, ({one, many}) => ({ + dataset: one(datasets, { + fields: [datasetDatapoints.datasetId], + references: [datasets.id] }), + datapointToSpans: many(datapointToSpan), })); -export const labelingQueuesRelations = relations(labelingQueues, ({one, many}) => ({ +export const datasetsRelations = relations(datasets, ({one, many}) => ({ + datasetDatapoints: many(datasetDatapoints), project: one(projects, { - fields: [labelingQueues.projectId], + fields: [datasets.projectId], references: [projects.id] }), - labelingQueueItems: many(labelingQueueItems), })); export const labelingQueueItemsRelations = relations(labelingQueueItems, ({one}) => ({ @@ -192,25 +171,46 @@ export const labelingQueueItemsRelations = relations(labelingQueueItems, ({one}) }), })); -export const tracesRelations = relations(traces, ({one, many}) => ({ - project: one(projects, { - fields: [traces.projectId], - references: [projects.id] +export const membersOfWorkspacesRelations = relations(membersOfWorkspaces, ({one}) => ({ + user: one(users, { + fields: [membersOfWorkspaces.userId], + references: [users.id] + }), + workspace: one(workspaces, { + fields: [membersOfWorkspaces.workspaceId], + references: [workspaces.id] }), - spans: many(spans), })); -export const evaluationsRelations = relations(evaluations, ({one, many}) => ({ - evaluationResults: many(evaluationResults), +export const projectApiKeysRelations = relations(projectApiKeys, ({one}) => ({ project: one(projects, { - fields: [evaluations.projectId], + fields: [projectApiKeys.projectId], references: [projects.id] }), })); -export const playgroundsRelations = relations(playgrounds, ({one}) => ({ +export const subscriptionTiersRelations = relations(subscriptionTiers, ({many}) => ({ + workspaces: many(workspaces), +})); + +export const userSubscriptionInfoRelations = relations(userSubscriptionInfo, ({one}) => ({ + user: one(users, { + fields: [userSubscriptionInfo.userId], + references: [users.id] + }), +})); + +export const labelsRelations = relations(labels, ({one}) => ({ + labelClass: one(labelClasses, { + fields: [labels.classId], + references: [labelClasses.id] + }), +})); + +export const labelClassesRelations = relations(labelClasses, ({one, many}) => ({ + labels: many(labels), project: one(projects, { - fields: [playgrounds.projectId], + fields: [labelClasses.projectId], references: [projects.id] }), })); diff --git a/frontend/lib/db/migrations/schema.ts b/frontend/lib/db/migrations/schema.ts index 890dcb0f..9b1389e7 100644 --- a/frontend/lib/db/migrations/schema.ts +++ b/frontend/lib/db/migrations/schema.ts @@ -1,4 +1,4 @@ -import { bigint, boolean, doublePrecision, foreignKey, index, integer, jsonb, pgEnum, pgTable, primaryKey, text, timestamp, unique, uuid } from "drizzle-orm/pg-core"; +import { bigint, boolean, doublePrecision, foreignKey, index, integer, jsonb, pgEnum, pgPolicy, pgTable, primaryKey, text, timestamp, unique, uuid } from "drizzle-orm/pg-core"; import { sql } from "drizzle-orm"; export const eventSource = pgEnum("event_source", ['AUTO', 'MANUAL', 'CODE']); @@ -10,90 +10,76 @@ export const traceType = pgEnum("trace_type", ['DEFAULT', 'EVENT', 'EVALUATION'] export const workspaceRole = pgEnum("workspace_role", ['member', 'owner']); -export const llmPrices = pgTable("llm_prices", { +export const targetPipelineVersions = pgTable("target_pipeline_versions", { id: uuid().defaultRandom().primaryKey().notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - provider: text().notNull(), - model: text().notNull(), - inputPricePerMillion: doublePrecision("input_price_per_million").notNull(), - outputPricePerMillion: doublePrecision("output_price_per_million").notNull(), - inputCachedPricePerMillion: doublePrecision("input_cached_price_per_million"), - additionalPrices: jsonb("additional_prices").default({}).notNull(), -}); + pipelineId: uuid("pipeline_id").notNull(), + pipelineVersionId: uuid("pipeline_version_id").notNull(), +}, (table) => ({ + targetPipelineVersionsPipelineIdFkey: foreignKey({ + columns: [table.pipelineId], + foreignColumns: [pipelines.id], + name: "target_pipeline_versions_pipeline_id_fkey" + }).onUpdate("cascade").onDelete("cascade"), + targetPipelineVersionsPipelineVersionIdFkey: foreignKey({ + columns: [table.pipelineVersionId], + foreignColumns: [pipelineVersions.id], + name: "target_pipeline_versions_pipeline_version_id_fkey" + }), + uniquePipelineId: unique("unique_pipeline_id").on(table.pipelineId), +})); -export const pipelineTemplates = pgTable("pipeline_templates", { +export const traces = pgTable("traces", { id: uuid().defaultRandom().primaryKey().notNull(), - createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - runnableGraph: jsonb("runnable_graph").default({}).notNull(), - displayableGraph: jsonb("displayable_graph").default({}).notNull(), + sessionId: text("session_id"), + metadata: jsonb(), + projectId: uuid("project_id").notNull(), + endTime: timestamp("end_time", { withTimezone: true, mode: 'string' }), + startTime: timestamp("start_time", { withTimezone: true, mode: 'string' }), // You can use { mode: "bigint" } if numbers are exceeding js number limitations - numberOfNodes: bigint("number_of_nodes", { mode: "number" }).notNull(), - name: text().default('').notNull(), - description: text().default('').notNull(), - displayGroup: text("display_group").default('build').notNull(), - ordinal: integer().default(500).notNull(), -}); - -export const datasets = pgTable("datasets", { - id: uuid().defaultRandom().primaryKey().notNull(), + totalTokenCount: bigint("total_token_count", { mode: "number" }).default(sql`'0'`).notNull(), + cost: doublePrecision().default(sql`'0'`).notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - name: text().notNull(), - projectId: uuid("project_id").defaultRandom().notNull(), - indexedOn: text("indexed_on"), + traceType: traceType("trace_type").default('DEFAULT').notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + inputTokenCount: bigint("input_token_count", { mode: "number" }).default(sql`'0'`).notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + outputTokenCount: bigint("output_token_count", { mode: "number" }).default(sql`'0'`).notNull(), + inputCost: doublePrecision("input_cost").default(sql`'0'`).notNull(), + outputCost: doublePrecision("output_cost").default(sql`'0'`).notNull(), }, (table) => ({ - publicDatasetsProjectIdFkey: foreignKey({ + traceMetadataGinIdx: index("trace_metadata_gin_idx").using("gin", table.metadata.asc().nullsLast()), + idProjectIdStartTimeTimesNotNullIdx: index("traces_id_project_id_start_time_times_not_null_idx").using("btree", table.id.asc().nullsLast(), table.projectId.asc().nullsLast(), table.startTime.desc().nullsFirst()).where(sql`((start_time IS NOT NULL) AND (end_time IS NOT NULL))`), + projectIdIdx: index("traces_project_id_idx").using("btree", table.projectId.asc().nullsLast()), + projectIdTraceTypeStartTimeEndTimeIdx: index("traces_project_id_trace_type_start_time_end_time_idx").using("btree", table.projectId.asc().nullsLast(), table.startTime.asc().nullsLast(), table.endTime.asc().nullsLast()).where(sql`((trace_type = 'DEFAULT'::trace_type) AND (start_time IS NOT NULL) AND (end_time IS NOT NULL))`), + sessionIdIdx: index("traces_session_id_idx").using("btree", table.sessionId.asc().nullsLast()), + startTimeEndTimeIdx: index("traces_start_time_end_time_idx").using("btree", table.startTime.asc().nullsLast(), table.endTime.asc().nullsLast()), + newTracesProjectIdFkey: foreignKey({ columns: [table.projectId], foreignColumns: [projects.id], - name: "public_datasets_project_id_fkey" + name: "new_traces_project_id_fkey" }).onUpdate("cascade").onDelete("cascade"), + selectByNextApiKey: pgPolicy("select_by_next_api_key", { as: "permissive", for: "select", to: ["anon", "authenticated"], using: sql`is_trace_id_accessible_for_api_key(api_key(), id)` }), })); -export const datasetDatapoints = pgTable("dataset_datapoints", { +export const evaluationResults = pgTable("evaluation_results", { id: uuid().defaultRandom().primaryKey().notNull(), - datasetId: uuid("dataset_id").notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), + evaluationId: uuid("evaluation_id").notNull(), data: jsonb().notNull(), - indexedOn: text("indexed_on"), - target: jsonb().default({}), + target: jsonb().default({}).notNull(), + executorOutput: jsonb("executor_output"), // You can use { mode: "bigint" } if numbers are exceeding js number limitations indexInBatch: bigint("index_in_batch", { mode: "number" }), - metadata: jsonb(), -}, (table) => ({ - datasetDatapointsDatasetIdFkey: foreignKey({ - columns: [table.datasetId], - foreignColumns: [datasets.id], - name: "dataset_datapoints_dataset_id_fkey" - }).onUpdate("cascade").onDelete("cascade"), -})); - -export const projects = pgTable("projects", { - id: uuid().defaultRandom().primaryKey().notNull(), - createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - name: text().notNull(), - workspaceId: uuid("workspace_id").notNull(), -}, (table) => ({ - workspaceIdIdx: index("projects_workspace_id_idx").using("btree", table.workspaceId.asc().nullsLast()), - projectsWorkspaceIdFkey: foreignKey({ - columns: [table.workspaceId], - foreignColumns: [workspaces.id], - name: "projects_workspace_id_fkey" - }).onUpdate("cascade").onDelete("cascade"), -})); - -export const eventTemplates = pgTable("event_templates", { - id: uuid().defaultRandom().primaryKey().notNull(), - createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - name: text().notNull(), - projectId: uuid("project_id").notNull(), - eventType: eventType("event_type").default('BOOLEAN').notNull(), + traceId: uuid("trace_id").notNull(), }, (table) => ({ - eventTemplatesProjectIdFkey: foreignKey({ - columns: [table.projectId], - foreignColumns: [projects.id], - name: "event_templates_project_id_fkey" + evaluationIdIdx: index("evaluation_results_evaluation_id_idx").using("btree", table.evaluationId.asc().nullsLast()), + evaluationResultsEvaluationIdFkey1: foreignKey({ + columns: [table.evaluationId], + foreignColumns: [evaluations.id], + name: "evaluation_results_evaluation_id_fkey1" }).onUpdate("cascade").onDelete("cascade"), - uniqueNameProjectId: unique("unique_name_project_id").on(table.name, table.projectId), + selectByNextApiKey: pgPolicy("select_by_next_api_key", { as: "permissive", for: "select", to: ["anon", "authenticated"], using: sql`is_evaluation_id_accessible_for_api_key(api_key(), evaluation_id)` }), })); export const events = pgTable("events", { @@ -115,264 +101,215 @@ export const events = pgTable("events", { }).onUpdate("cascade").onDelete("cascade"), })); -export const labelClasses = pgTable("label_classes", { +export const labelingQueues = pgTable("labeling_queues", { id: uuid().defaultRandom().primaryKey().notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), name: text().notNull(), projectId: uuid("project_id").notNull(), - labelType: labelType("label_type").notNull(), - valueMap: jsonb("value_map").default([false,true]).notNull(), - description: text(), - evaluatorRunnableGraph: jsonb("evaluator_runnable_graph"), - pipelineVersionId: uuid("pipeline_version_id"), }, (table) => ({ - labelClassesProjectIdFkey: foreignKey({ + labelingQueuesProjectIdFkey: foreignKey({ columns: [table.projectId], foreignColumns: [projects.id], - name: "label_classes_project_id_fkey" + name: "labeling_queues_project_id_fkey" }).onUpdate("cascade").onDelete("cascade"), })); -export const labelClassesForPath = pgTable("label_classes_for_path", { +export const providerApiKeys = pgTable("provider_api_keys", { id: uuid().defaultRandom().primaryKey().notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), + name: text().notNull(), projectId: uuid("project_id").defaultRandom().notNull(), - path: text().notNull(), - labelClassId: uuid("label_class_id").notNull(), + nonceHex: text("nonce_hex").notNull(), + value: text().notNull(), }, (table) => ({ - autoevalLabelsProjectIdFkey: foreignKey({ + providerApiKeysProjectIdFkey: foreignKey({ columns: [table.projectId], foreignColumns: [projects.id], - name: "autoeval_labels_project_id_fkey" - }).onUpdate("cascade").onDelete("cascade"), - uniqueProjectIdPathLabelClass: unique("unique_project_id_path_label_class").on(table.projectId, table.path, table.labelClassId), -})); - -export const labels = pgTable("labels", { - id: uuid().defaultRandom().primaryKey().notNull(), - createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - classId: uuid("class_id").notNull(), - value: doublePrecision().default(sql`'0'`).notNull(), - spanId: uuid("span_id").notNull(), - updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - userId: uuid("user_id").defaultRandom(), - labelSource: labelSource("label_source").default('MANUAL').notNull(), - reasoning: text(), -}, (table) => ({ - traceTagsTypeIdFkey: foreignKey({ - columns: [table.classId], - foreignColumns: [labelClasses.id], - name: "trace_tags_type_id_fkey" + name: "provider_api_keys_project_id_fkey" }).onUpdate("cascade").onDelete("cascade"), - labelsSpanIdClassIdUserIdKey: unique("labels_span_id_class_id_user_id_key").on(table.classId, table.spanId, table.userId), })); -export const membersOfWorkspaces = pgTable("members_of_workspaces", { - workspaceId: uuid("workspace_id").notNull(), - userId: uuid("user_id").notNull(), - createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - id: uuid().defaultRandom().primaryKey().notNull(), - memberRole: workspaceRole("member_role").default('owner').notNull(), +export const workspaceUsage = pgTable("workspace_usage", { + workspaceId: uuid("workspace_id").defaultRandom().primaryKey().notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + spanCount: bigint("span_count", { mode: "number" }).default(sql`'0'`).notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + spanCountSinceReset: bigint("span_count_since_reset", { mode: "number" }).default(sql`'0'`).notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + prevSpanCount: bigint("prev_span_count", { mode: "number" }).default(sql`'0'`).notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + eventCount: bigint("event_count", { mode: "number" }).default(sql`'0'`).notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + eventCountSinceReset: bigint("event_count_since_reset", { mode: "number" }).default(sql`'0'`).notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + prevEventCount: bigint("prev_event_count", { mode: "number" }).default(sql`'0'`).notNull(), + resetTime: timestamp("reset_time", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), + resetReason: text("reset_reason").default('signup').notNull(), }, (table) => ({ - userIdIdx: index("members_of_workspaces_user_id_idx").using("btree", table.userId.asc().nullsLast()), - membersOfWorkspacesUserIdFkey: foreignKey({ - columns: [table.userId], - foreignColumns: [users.id], - name: "members_of_workspaces_user_id_fkey" - }).onUpdate("cascade").onDelete("cascade"), - publicMembersOfWorkspacesWorkspaceIdFkey: foreignKey({ + userUsageWorkspaceIdFkey: foreignKey({ columns: [table.workspaceId], foreignColumns: [workspaces.id], - name: "public_members_of_workspaces_workspace_id_fkey" + name: "user_usage_workspace_id_fkey" }).onUpdate("cascade").onDelete("cascade"), - membersOfWorkspacesUserWorkspaceUnique: unique("members_of_workspaces_user_workspace_unique").on(table.workspaceId, table.userId), + userUsageWorkspaceIdKey: unique("user_usage_workspace_id_key").on(table.workspaceId), })); -export const apiKeys = pgTable("api_keys", { - apiKey: text("api_key").primaryKey().notNull(), +export const evaluations = pgTable("evaluations", { + id: uuid().defaultRandom().primaryKey().notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - userId: uuid("user_id").notNull(), - name: text().default('default').notNull(), + projectId: uuid("project_id").notNull(), + name: text().notNull(), + groupId: text("group_id").default('default').notNull(), }, (table) => ({ - userIdIdx: index("api_keys_user_id_idx").using("btree", table.userId.asc().nullsLast()), - apiKeysUserIdFkey: foreignKey({ - columns: [table.userId], - foreignColumns: [users.id], - name: "api_keys_user_id_fkey" + evaluationsProjectIdFkey1: foreignKey({ + columns: [table.projectId], + foreignColumns: [projects.id], + name: "evaluations_project_id_fkey1" }).onUpdate("cascade").onDelete("cascade"), + selectByNextApiKey: pgPolicy("select_by_next_api_key", { as: "permissive", for: "select", to: ["anon", "authenticated"], using: sql`is_evaluation_id_accessible_for_api_key(api_key(), id)` }), })); -export const workspaces = pgTable("workspaces", { - id: uuid().defaultRandom().primaryKey().notNull(), +export const subscriptionTiers = pgTable("subscription_tiers", { + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + id: bigint({ mode: "number" }).primaryKey().generatedByDefaultAsIdentity({ name: "subscription_tiers_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 9223372036854775807, cache: 1 }), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), name: text().notNull(), // You can use { mode: "bigint" } if numbers are exceeding js number limitations - tierId: bigint("tier_id", { mode: "number" }).default(sql`'1'`).notNull(), - subscriptionId: text("subscription_id").default('').notNull(), + storageMib: bigint("storage_mib", { mode: "number" }).notNull(), // You can use { mode: "bigint" } if numbers are exceeding js number limitations - additionalSeats: bigint("additional_seats", { mode: "number" }).default(sql`'0'`).notNull(), -}, (table) => ({ - workspacesTierIdFkey: foreignKey({ - columns: [table.tierId], - foreignColumns: [subscriptionTiers.id], - name: "workspaces_tier_id_fkey" - }).onUpdate("cascade"), -})); + logRetentionDays: bigint("log_retention_days", { mode: "number" }).notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + membersPerWorkspace: bigint("members_per_workspace", { mode: "number" }).default(sql`'-1'`).notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + numWorkspaces: bigint("num_workspaces", { mode: "number" }).default(sql`'-1'`).notNull(), + stripeProductId: text("stripe_product_id").default('').notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + events: bigint({ mode: "number" }).default(sql`'0'`).notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + spans: bigint({ mode: "number" }).default(sql`'0'`).notNull(), + extraSpanPrice: doublePrecision("extra_span_price").default(sql`'0'`).notNull(), + extraEventPrice: doublePrecision("extra_event_price").default(sql`'0'`).notNull(), +}); -export const pipelines = pgTable("pipelines", { +export const eventTemplates = pgTable("event_templates", { id: uuid().defaultRandom().primaryKey().notNull(), - projectId: uuid("project_id").notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), name: text().notNull(), - visibility: text().default('PRIVATE').notNull(), - pythonRequirements: text("python_requirements").default('').notNull(), + projectId: uuid("project_id").notNull(), + eventType: eventType("event_type").default('BOOLEAN').notNull(), }, (table) => ({ - nameProjectIdIdx: index("pipelines_name_project_id_idx").using("btree", table.name.asc().nullsLast(), table.projectId.asc().nullsLast()), - projectIdIdx: index("pipelines_project_id_idx").using("btree", table.projectId.asc().nullsLast()), - pipelinesProjectIdFkey: foreignKey({ + eventTemplatesProjectIdFkey: foreignKey({ columns: [table.projectId], foreignColumns: [projects.id], - name: "pipelines_project_id_fkey" + name: "event_templates_project_id_fkey" }).onUpdate("cascade").onDelete("cascade"), - uniqueProjectIdPipelineName: unique("unique_project_id_pipeline_name").on(table.projectId, table.name), + uniqueNameProjectId: unique("unique_name_project_id").on(table.name, table.projectId), })); -export const projectApiKeys = pgTable("project_api_keys", { - value: text().default('').notNull(), +export const evaluationScores = pgTable("evaluation_scores", { + id: uuid().defaultRandom().primaryKey().notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - name: text(), - projectId: uuid("project_id").notNull(), - shorthand: text().default('').notNull(), - hash: text().default('').notNull(), - id: uuid().defaultRandom().primaryKey().notNull(), + resultId: uuid("result_id").defaultRandom().notNull(), + name: text().default('').notNull(), + score: doublePrecision().notNull(), + labelId: uuid("label_id"), }, (table) => ({ - publicProjectApiKeysProjectIdFkey: foreignKey({ - columns: [table.projectId], - foreignColumns: [projects.id], - name: "public_project_api_keys_project_id_fkey" + resultIdIdx: index("evaluation_scores_result_id_idx").using("hash", table.resultId.asc().nullsLast()), + evaluationScoresResultIdFkey: foreignKey({ + columns: [table.resultId], + foreignColumns: [evaluationResults.id], + name: "evaluation_scores_result_id_fkey" }).onUpdate("cascade").onDelete("cascade"), + evaluationResultsNamesUnique: unique("evaluation_results_names_unique").on(table.resultId, table.name), })); -export const providerApiKeys = pgTable("provider_api_keys", { +export const llmPrices = pgTable("llm_prices", { + id: uuid().defaultRandom().primaryKey().notNull(), + createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), + updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), + provider: text().notNull(), + model: text().notNull(), + inputPricePerMillion: doublePrecision("input_price_per_million").notNull(), + outputPricePerMillion: doublePrecision("output_price_per_million").notNull(), + inputCachedPricePerMillion: doublePrecision("input_cached_price_per_million"), + additionalPrices: jsonb("additional_prices").default({}).notNull(), +}); + +export const playgrounds = pgTable("playgrounds", { id: uuid().defaultRandom().primaryKey().notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), name: text().notNull(), - projectId: uuid("project_id").defaultRandom().notNull(), - nonceHex: text("nonce_hex").notNull(), - value: text().notNull(), + projectId: uuid("project_id").notNull(), + promptMessages: jsonb("prompt_messages").default([{"role":"user","content":""}]).notNull(), + modelId: text("model_id").default('').notNull(), + outputSchema: text("output_schema"), }, (table) => ({ - providerApiKeysProjectIdFkey: foreignKey({ + playgroundsProjectIdFkey: foreignKey({ columns: [table.projectId], foreignColumns: [projects.id], - name: "provider_api_keys_project_id_fkey" + name: "playgrounds_project_id_fkey" }).onUpdate("cascade").onDelete("cascade"), })); -export const targetPipelineVersions = pgTable("target_pipeline_versions", { +export const labelClassesForPath = pgTable("label_classes_for_path", { id: uuid().defaultRandom().primaryKey().notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - pipelineId: uuid("pipeline_id").notNull(), - pipelineVersionId: uuid("pipeline_version_id").notNull(), + projectId: uuid("project_id").defaultRandom().notNull(), + path: text().notNull(), + labelClassId: uuid("label_class_id").notNull(), }, (table) => ({ - targetPipelineVersionsPipelineIdFkey: foreignKey({ - columns: [table.pipelineId], - foreignColumns: [pipelines.id], - name: "target_pipeline_versions_pipeline_id_fkey" + autoevalLabelsProjectIdFkey: foreignKey({ + columns: [table.projectId], + foreignColumns: [projects.id], + name: "autoeval_labels_project_id_fkey" }).onUpdate("cascade").onDelete("cascade"), - targetPipelineVersionsPipelineVersionIdFkey: foreignKey({ - columns: [table.pipelineVersionId], - foreignColumns: [pipelineVersions.id], - name: "target_pipeline_versions_pipeline_version_id_fkey" - }), - uniquePipelineId: unique("unique_pipeline_id").on(table.pipelineId), + uniqueProjectIdPathLabelClass: unique("unique_project_id_path_label_class").on(table.projectId, table.path, table.labelClassId), })); -export const userSubscriptionInfo = pgTable("user_subscription_info", { - userId: uuid("user_id").defaultRandom().primaryKey().notNull(), +export const apiKeys = pgTable("api_keys", { + apiKey: text("api_key").primaryKey().notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - stripeCustomerId: text("stripe_customer_id").notNull(), - activated: boolean().default(false).notNull(), + userId: uuid("user_id").notNull(), + name: text().default('default').notNull(), }, (table) => ({ - stripeCustomerIdIdx: index("user_subscription_info_stripe_customer_id_idx").using("btree", table.stripeCustomerId.asc().nullsLast()), - userSubscriptionInfoFkey: foreignKey({ + userIdIdx: index("api_keys_user_id_idx").using("btree", table.userId.asc().nullsLast()), + apiKeysUserIdFkey: foreignKey({ columns: [table.userId], foreignColumns: [users.id], - name: "user_subscription_info_fkey" - }).onUpdate("cascade").onDelete("cascade"), -})); - -export const workspaceUsage = pgTable("workspace_usage", { - workspaceId: uuid("workspace_id").defaultRandom().notNull(), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - spanCount: bigint("span_count", { mode: "number" }).default(sql`'0'`).notNull(), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - spanCountSinceReset: bigint("span_count_since_reset", { mode: "number" }).default(sql`'0'`).notNull(), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - prevSpanCount: bigint("prev_span_count", { mode: "number" }).default(sql`'0'`).notNull(), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - eventCount: bigint("event_count", { mode: "number" }).default(sql`'0'`).notNull(), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - eventCountSinceReset: bigint("event_count_since_reset", { mode: "number" }).default(sql`'0'`).notNull(), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - prevEventCount: bigint("prev_event_count", { mode: "number" }).default(sql`'0'`).notNull(), - resetTime: timestamp("reset_time", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - resetReason: text("reset_reason").default('signup').notNull(), -}, (table) => ({ - userUsageWorkspaceIdFkey: foreignKey({ - columns: [table.workspaceId], - foreignColumns: [workspaces.id], - name: "user_usage_workspace_id_fkey" + name: "api_keys_user_id_fkey" }).onUpdate("cascade").onDelete("cascade"), + enableInsertForAuthenticatedUsersOnly: pgPolicy("Enable insert for authenticated users only", { as: "permissive", for: "all", to: ["service_role"], using: sql`true`, withCheck: sql`true` }), })); -export const subscriptionTiers = pgTable("subscription_tiers", { - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - id: bigint({ mode: "number" }).primaryKey().generatedByDefaultAsIdentity({ name: "subscription_tiers_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 9223372036854775000, cache: 1 }), - createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - name: text().notNull(), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - storageMib: bigint("storage_mib", { mode: "number" }).notNull(), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - logRetentionDays: bigint("log_retention_days", { mode: "number" }).notNull(), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - membersPerWorkspace: bigint("members_per_workspace", { mode: "number" }).default(sql`'-1'`).notNull(), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - numWorkspaces: bigint("num_workspaces", { mode: "number" }).default(sql`'-1'`).notNull(), - stripeProductId: text("stripe_product_id").default('').notNull(), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - events: bigint({ mode: "number" }).default(sql`'0'`).notNull(), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - spans: bigint({ mode: "number" }).default(sql`'0'`).notNull(), - extraSpanPrice: doublePrecision("extra_span_price").default(sql`'0'`).notNull(), - extraEventPrice: doublePrecision("extra_event_price").default(sql`'0'`).notNull(), -}); - -export const evaluationScores = pgTable("evaluation_scores", { +export const datasetDatapoints = pgTable("dataset_datapoints", { id: uuid().defaultRandom().primaryKey().notNull(), + datasetId: uuid("dataset_id").notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - resultId: uuid("result_id").defaultRandom().notNull(), - name: text().default('').notNull(), - score: doublePrecision().notNull(), + data: jsonb().notNull(), + indexedOn: text("indexed_on"), + target: jsonb().default({}), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + indexInBatch: bigint("index_in_batch", { mode: "number" }), + metadata: jsonb(), }, (table) => ({ - resultIdIdx: index("evaluation_scores_result_id_idx").using("hash", table.resultId.asc().nullsLast()), - evaluationScoresResultIdFkey: foreignKey({ - columns: [table.resultId], - foreignColumns: [evaluationResults.id], - name: "evaluation_scores_result_id_fkey" + datasetDatapointsDatasetIdFkey: foreignKey({ + columns: [table.datasetId], + foreignColumns: [datasets.id], + name: "dataset_datapoints_dataset_id_fkey" }).onUpdate("cascade").onDelete("cascade"), - evaluationResultsNamesUnique: unique("evaluation_results_names_unique").on(table.resultId, table.name), })); -export const labelingQueues = pgTable("labeling_queues", { +export const datasets = pgTable("datasets", { id: uuid().defaultRandom().primaryKey().notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), name: text().notNull(), - projectId: uuid("project_id").notNull(), + projectId: uuid("project_id").defaultRandom().notNull(), + indexedOn: text("indexed_on"), }, (table) => ({ - labelingQueuesProjectIdFkey: foreignKey({ + publicDatasetsProjectIdFkey: foreignKey({ columns: [table.projectId], foreignColumns: [projects.id], - name: "labeling_queues_project_id_fkey" + name: "public_datasets_project_id_fkey" }).onUpdate("cascade").onDelete("cascade"), })); @@ -390,6 +327,45 @@ export const labelingQueueItems = pgTable("labeling_queue_items", { }).onUpdate("cascade").onDelete("cascade"), })); +export const membersOfWorkspaces = pgTable("members_of_workspaces", { + workspaceId: uuid("workspace_id").notNull(), + userId: uuid("user_id").notNull(), + createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), + id: uuid().defaultRandom().primaryKey().notNull(), + memberRole: workspaceRole("member_role").default('owner').notNull(), +}, (table) => ({ + userIdIdx: index("members_of_workspaces_user_id_idx").using("btree", table.userId.asc().nullsLast()), + membersOfWorkspacesUserIdFkey: foreignKey({ + columns: [table.userId], + foreignColumns: [users.id], + name: "members_of_workspaces_user_id_fkey" + }).onUpdate("cascade").onDelete("cascade"), + publicMembersOfWorkspacesWorkspaceIdFkey: foreignKey({ + columns: [table.workspaceId], + foreignColumns: [workspaces.id], + name: "public_members_of_workspaces_workspace_id_fkey" + }).onUpdate("cascade").onDelete("cascade"), + membersOfWorkspacesUserWorkspaceUnique: unique("members_of_workspaces_user_workspace_unique").on(table.workspaceId, table.userId), +})); + +export const pipelines = pgTable("pipelines", { + id: uuid().defaultRandom().primaryKey().notNull(), + projectId: uuid("project_id").notNull(), + createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), + name: text().notNull(), + visibility: text().default('PRIVATE').notNull(), + pythonRequirements: text("python_requirements").default('').notNull(), +}, (table) => ({ + nameProjectIdIdx: index("pipelines_name_project_id_idx").using("btree", table.name.asc().nullsLast(), table.projectId.asc().nullsLast()), + projectIdIdx: index("pipelines_project_id_idx").using("btree", table.projectId.asc().nullsLast()), + pipelinesProjectIdFkey: foreignKey({ + columns: [table.projectId], + foreignColumns: [projects.id], + name: "pipelines_project_id_fkey" + }).onUpdate("cascade").onDelete("cascade"), + uniqueProjectIdPipelineName: unique("unique_project_id_pipeline_name").on(table.projectId, table.name), +})); + export const pipelineVersions = pgTable("pipeline_versions", { id: uuid().defaultRandom().primaryKey().notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), @@ -398,71 +374,55 @@ export const pipelineVersions = pgTable("pipeline_versions", { runnableGraph: jsonb("runnable_graph").notNull(), pipelineType: text("pipeline_type").notNull(), name: text().notNull(), -}); +}, (table) => ({ + allActionsByNextApiKey: pgPolicy("all_actions_by_next_api_key", { as: "permissive", for: "all", to: ["anon", "authenticated"], using: sql`is_pipeline_id_accessible_for_api_key(api_key(), pipeline_id)` }), +})); -export const traces = pgTable("traces", { +export const projects = pgTable("projects", { id: uuid().defaultRandom().primaryKey().notNull(), - sessionId: text("session_id"), - metadata: jsonb(), - projectId: uuid("project_id").notNull(), - endTime: timestamp("end_time", { withTimezone: true, mode: 'string' }), - startTime: timestamp("start_time", { withTimezone: true, mode: 'string' }), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - totalTokenCount: bigint("total_token_count", { mode: "number" }).default(sql`'0'`).notNull(), - cost: doublePrecision().default(sql`'0'`).notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - traceType: traceType("trace_type").default('DEFAULT').notNull(), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - inputTokenCount: bigint("input_token_count", { mode: "number" }).default(sql`'0'`).notNull(), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - outputTokenCount: bigint("output_token_count", { mode: "number" }).default(sql`'0'`).notNull(), - inputCost: doublePrecision("input_cost").default(sql`'0'`).notNull(), - outputCost: doublePrecision("output_cost").default(sql`'0'`).notNull(), + name: text().notNull(), + workspaceId: uuid("workspace_id").notNull(), }, (table) => ({ - traceMetadataGinIdx: index("trace_metadata_gin_idx").using("gin", table.metadata.asc().nullsLast()), - idProjectIdStartTimeTimesNotNullIdx: index("traces_id_project_id_start_time_times_not_null_idx").using("btree", table.id.asc().nullsLast(), table.projectId.asc().nullsLast(), table.startTime.desc().nullsFirst()).where(sql`((start_time IS NOT NULL) AND (end_time IS NOT NULL))`), - projectIdIdx: index("traces_project_id_idx").using("btree", table.projectId.asc().nullsLast()), - projectIdTraceTypeStartTimeEndTimeIdx: index("traces_project_id_trace_type_start_time_end_time_idx").using("btree", table.projectId.asc().nullsLast(), table.startTime.asc().nullsLast(), table.endTime.asc().nullsLast()).where(sql`((trace_type = 'DEFAULT'::trace_type) AND (start_time IS NOT NULL) AND (end_time IS NOT NULL))`), - sessionIdIdx: index("traces_session_id_idx").using("btree", table.sessionId.asc().nullsLast()), - startTimeEndTimeIdx: index("traces_start_time_end_time_idx").using("btree", table.startTime.asc().nullsLast(), table.endTime.asc().nullsLast()), - newTracesProjectIdFkey: foreignKey({ - columns: [table.projectId], - foreignColumns: [projects.id], - name: "new_traces_project_id_fkey" + workspaceIdIdx: index("projects_workspace_id_idx").using("btree", table.workspaceId.asc().nullsLast()), + projectsWorkspaceIdFkey: foreignKey({ + columns: [table.workspaceId], + foreignColumns: [workspaces.id], + name: "projects_workspace_id_fkey" }).onUpdate("cascade").onDelete("cascade"), })); -export const evaluationResults = pgTable("evaluation_results", { - id: uuid().defaultRandom().primaryKey().notNull(), +export const projectApiKeys = pgTable("project_api_keys", { + value: text().default('').notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - evaluationId: uuid("evaluation_id").notNull(), - data: jsonb().notNull(), - target: jsonb().default({}).notNull(), - executorOutput: jsonb("executor_output"), - // You can use { mode: "bigint" } if numbers are exceeding js number limitations - indexInBatch: bigint("index_in_batch", { mode: "number" }), - traceId: uuid("trace_id").notNull(), + name: text(), + projectId: uuid("project_id").notNull(), + shorthand: text().default('').notNull(), + hash: text().default('').notNull(), + id: uuid().defaultRandom().primaryKey().notNull(), }, (table) => ({ - evaluationIdIdx: index("evaluation_results_evaluation_id_idx").using("btree", table.evaluationId.asc().nullsLast()), - evaluationResultsEvaluationIdFkey1: foreignKey({ - columns: [table.evaluationId], - foreignColumns: [evaluations.id], - name: "evaluation_results_evaluation_id_fkey1" + publicProjectApiKeysProjectIdFkey: foreignKey({ + columns: [table.projectId], + foreignColumns: [projects.id], + name: "public_project_api_keys_project_id_fkey" }).onUpdate("cascade").onDelete("cascade"), })); -export const evaluations = pgTable("evaluations", { +export const workspaces = pgTable("workspaces", { id: uuid().defaultRandom().primaryKey().notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), - projectId: uuid("project_id").notNull(), name: text().notNull(), - groupId: text("group_id").default('default').notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + tierId: bigint("tier_id", { mode: "number" }).default(sql`'1'`).notNull(), + subscriptionId: text("subscription_id").default('').notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + additionalSeats: bigint("additional_seats", { mode: "number" }).default(sql`'0'`).notNull(), }, (table) => ({ - evaluationsProjectIdFkey1: foreignKey({ - columns: [table.projectId], - foreignColumns: [projects.id], - name: "evaluations_project_id_fkey1" - }).onUpdate("cascade").onDelete("cascade"), + workspacesTierIdFkey: foreignKey({ + columns: [table.tierId], + foreignColumns: [subscriptionTiers.id], + name: "workspaces_tier_id_fkey" + }).onUpdate("cascade"), })); export const users = pgTable("users", { @@ -472,21 +432,70 @@ export const users = pgTable("users", { email: text().notNull(), }, (table) => ({ usersEmailKey: unique("users_email_key").on(table.email), + enableInsertForAuthenticatedUsersOnly: pgPolicy("Enable insert for authenticated users only", { as: "permissive", for: "insert", to: ["service_role"], withCheck: sql`true` }), })); -export const playgrounds = pgTable("playgrounds", { +export const userSubscriptionInfo = pgTable("user_subscription_info", { + userId: uuid("user_id").defaultRandom().primaryKey().notNull(), + createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), + stripeCustomerId: text("stripe_customer_id").notNull(), + activated: boolean().default(false).notNull(), +}, (table) => ({ + stripeCustomerIdIdx: index("user_subscription_info_stripe_customer_id_idx").using("btree", table.stripeCustomerId.asc().nullsLast()), + userSubscriptionInfoFkey: foreignKey({ + columns: [table.userId], + foreignColumns: [users.id], + name: "user_subscription_info_fkey" + }).onUpdate("cascade").onDelete("cascade"), +})); + +export const pipelineTemplates = pgTable("pipeline_templates", { + id: uuid().defaultRandom().primaryKey().notNull(), + createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), + runnableGraph: jsonb("runnable_graph").default({}).notNull(), + displayableGraph: jsonb("displayable_graph").default({}).notNull(), + // You can use { mode: "bigint" } if numbers are exceeding js number limitations + numberOfNodes: bigint("number_of_nodes", { mode: "number" }).notNull(), + name: text().default('').notNull(), + description: text().default('').notNull(), + displayGroup: text("display_group").default('build').notNull(), + ordinal: integer().default(500).notNull(), +}); + +export const labels = pgTable("labels", { + id: uuid().defaultRandom().primaryKey().notNull(), + createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), + classId: uuid("class_id").notNull(), + value: doublePrecision().default(sql`'0'`).notNull(), + spanId: uuid("span_id").notNull(), + updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), + userId: uuid("user_id").defaultRandom(), + labelSource: labelSource("label_source").default('MANUAL').notNull(), + reasoning: text(), +}, (table) => ({ + traceTagsTypeIdFkey: foreignKey({ + columns: [table.classId], + foreignColumns: [labelClasses.id], + name: "trace_tags_type_id_fkey" + }).onUpdate("cascade").onDelete("cascade"), + labelsSpanIdClassIdUserIdKey: unique("labels_span_id_class_id_user_id_key").on(table.classId, table.spanId, table.userId), +})); + +export const labelClasses = pgTable("label_classes", { id: uuid().defaultRandom().primaryKey().notNull(), createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), name: text().notNull(), projectId: uuid("project_id").notNull(), - promptMessages: jsonb("prompt_messages").default([{"role":"user","content":""}]).notNull(), - modelId: text("model_id").default('').notNull(), - outputSchema: text("output_schema"), + labelType: labelType("label_type").notNull(), + valueMap: jsonb("value_map").default([false,true]).notNull(), + description: text(), + evaluatorRunnableGraph: jsonb("evaluator_runnable_graph"), + pipelineVersionId: uuid("pipeline_version_id"), }, (table) => ({ - playgroundsProjectIdFkey: foreignKey({ + labelClassesProjectIdFkey: foreignKey({ columns: [table.projectId], foreignColumns: [projects.id], - name: "playgrounds_project_id_fkey" + name: "label_classes_project_id_fkey" }).onUpdate("cascade").onDelete("cascade"), })); diff --git a/frontend/lib/traces/types.ts b/frontend/lib/traces/types.ts index ee1a7368..99029409 100644 --- a/frontend/lib/traces/types.ts +++ b/frontend/lib/traces/types.ts @@ -61,7 +61,7 @@ export type Span = { name: string; startTime: string; endTime: string; - attributes: any; + attributes: Record; input: any | null; output: any | null; inputPreview: string | null;