Merge branch 'evals' of https://github.com/buster-so/buster into evals

This commit is contained in:
Nate Kelley 2025-04-04 16:51:40 -06:00
commit 6841eef90a
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
20 changed files with 45 additions and 93 deletions

View File

@ -74,7 +74,8 @@ redis = { version = "0.27.5", features = [
"tls-rustls-webpki-roots",
] }
resend-rs = "0.10.0"
sentry = { version = "0.35.0", features = ["tokio", "sentry-tracing"] }
sentry = { version = "0.37.0", features = ["tokio", "sentry-tracing"] }
sentry-tower = { version = "0.37.0", features = ["axum", "http"] }
serde_urlencoded = "0.7.1"
snowflake-api = "0.11.0"
tempfile = "3.10.1"
@ -89,6 +90,7 @@ tiberius = { version = "0.12.2", default-features = false, features = [
tiktoken-rs = "0.6.0"
tokio-stream = "0.1.15"
tokio-util = { version = "0.7.11", features = ["compat"] }
tower = { version = "0.5.2" }
tower-http = { version = "0.6.2", features = [
"cors",
"trace",
@ -106,5 +108,5 @@ incremental = true
[profile.dev]
incremental = true
opt-level = 0 # Ensure this is 0 for faster debug builds
debug = 1 # Reduce debug info slightly while keeping enough for backtraces
opt-level = 0 # Ensure this is 0 for faster debug builds
debug = 1 # Reduce debug info slightly while keeping enough for backtraces

View File

@ -9,7 +9,6 @@ edition = "2021"
anyhow = { workspace = true }
serde = { workspace = true }
tokio = { workspace = true }
thiserror = { workspace = true }
async-trait = { workspace = true }
uuid = { workspace = true }
litellm = { path = "../litellm" }
@ -18,8 +17,6 @@ query_engine = { path = "../query_engine" }
braintrust = { path = "../braintrust" }
serde_json = { workspace = true }
futures = { workspace = true }
futures-util = { workspace = true }
sqlparser = { workspace = true }
chrono = { workspace = true }
diesel = { workspace = true }
diesel-async = { workspace = true }

View File

@ -14,7 +14,6 @@ tokio = { workspace = true }
tracing = { workspace = true }
uuid = { workspace = true }
reqwest = { workspace = true }
tokio-stream = { workspace = true }
# Development dependencies
[dev-dependencies]

View File

@ -14,7 +14,6 @@ serde_json = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
uuid = { workspace = true }
async-trait = { workspace = true }
futures = { workspace = true }
indexmap = { workspace = true }
once_cell = { workspace = true }

View File

@ -16,13 +16,9 @@ uuid = { workspace = true }
diesel = { workspace = true }
diesel-async = { workspace = true }
futures = { workspace = true }
redis = { workspace = true }
regex = { workspace = true }
indexmap = { workspace = true }
async-trait = { workspace = true }
once_cell = { workspace = true }
base64 = { workspace = true }
sha2 = { workspace = true }
# Local dependencies
database = { path = "../database" }

View File

@ -9,9 +9,6 @@ anyhow = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
async-trait = { workspace = true }
futures = { workspace = true }
futures-util = { workspace = true }
reqwest = { workspace = true }
dotenv = { workspace = true }

View File

@ -26,7 +26,6 @@ tokio-util = { workspace = true }
rand = { workspace = true }
futures = { workspace = true }
sqlparser = { workspace = true }
once_cell = { workspace = true }
num-traits = { workspace = true }
reqwest = { workspace = true }

View File

@ -9,7 +9,6 @@ chrono = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
uuid = { workspace = true }
sqlx = { workspace = true }
tokio-stream = { workspace = true }

View File

@ -7,7 +7,6 @@ edition = "2021"
anyhow = { workspace = true }
chrono = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
uuid = { workspace = true }

View File

@ -8,8 +8,6 @@ sqlparser = { workspace = true } # For SQL parsing
tokio = { workspace = true } # For async operations
anyhow = { workspace = true } # For error handling
serde = { workspace = true } # For serialization
serde_json = { workspace = true } # For JSON output
tracing = { workspace = true } # For logging
thiserror = { workspace = true } # For custom errors
regex = { workspace = true } # For pattern matching

View File

@ -9,12 +9,8 @@ default-run = "buster_server"
[dependencies]
# Use workspace dependencies
anyhow = { workspace = true }
arrow = { workspace = true }
async-compression = { workspace = true }
async-trait = { workspace = true }
axum = { workspace = true }
base64 = { workspace = true }
bb8-redis = { workspace = true }
chrono = { workspace = true }
cohere-rust = { workspace = true }
diesel = { workspace = true }
@ -22,43 +18,27 @@ diesel-async = { workspace = true }
diesel_migrations = { workspace = true }
dotenv = { workspace = true }
futures = { workspace = true }
futures-util = { workspace = true }
gcp-bigquery-client = { workspace = true }
html-escape = { workspace = true }
indexmap = { workspace = true }
jsonwebtoken = { workspace = true }
lazy_static = { workspace = true }
num-traits = { workspace = true }
once_cell = { workspace = true }
rand = { workspace = true }
rayon = { workspace = true }
redis = { workspace = true }
regex = { workspace = true }
reqwest = { workspace = true }
resend-rs = { workspace = true }
rustls = { workspace = true }
rustls-native-certs = { workspace = true }
sentry = { workspace = true }
sentry-tower = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
serde_urlencoded = { workspace = true }
serde_yaml = { workspace = true }
snowflake-api = { workspace = true }
sqlx = { workspace = true }
tempfile = { workspace = true }
tiberius = { workspace = true }
tiktoken-rs = { workspace = true }
tokio = { workspace = true }
tokio-postgres = { workspace = true }
tokio-postgres-rustls = { workspace = true }
tokio-stream = { workspace = true }
tokio-util = { workspace = true }
tower = { workspace = true }
tower-http = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
url = { workspace = true }
uuid = { workspace = true }
sqlparser = { workspace = true }
# Local dependencies
handlers = { path = "../libs/handlers" }
@ -66,7 +46,6 @@ litellm = { path = "../libs/litellm" }
database = { path = "../libs/database" }
agents = { path = "../libs/agents" }
query_engine = { path = "../libs/query_engine" }
braintrust = { path = "../libs/braintrust" }
middleware = { path = "../libs/middleware" }
sharing = { path = "../libs/sharing" }
search = { path = "../libs/search" }

View File

@ -4,7 +4,7 @@ pub mod utils;
use std::env;
use std::sync::Arc;
use axum::{Extension, Router};
use axum::{Extension, Router, extract::Request};
use middleware::cors::cors;
use database::{self, pool::init_pools};
use diesel::{Connection, PgConnection};
@ -12,6 +12,7 @@ use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
use dotenv::dotenv;
use rustls::crypto::ring;
use tokio::sync::broadcast;
use tower::ServiceBuilder;
use tower_http::{compression::CompressionLayer, trace::TraceLayer};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
@ -23,16 +24,26 @@ async fn main() {
dotenv().ok();
let environment = env::var("ENVIRONMENT").unwrap_or_else(|_| "development".to_string());
let is_development = environment == "development";
ring::default_provider()
.install_default()
.expect("Failed to install default crypto provider");
let _guard = sentry::init(("https://a417fbed1de30d2714a8afbe38d5bc1b@o4505360096428032.ingest.us.sentry.io/4507360721043456", sentry::ClientOptions {
release: sentry::release_name!(),
environment: Some(environment.into()),
..Default::default()
}));
// Only initialize Sentry if not in development environment
let _guard = if !is_development {
Some(sentry::init((
"https://a417fbed1de30d2714a8afbe38d5bc1b@o4505360096428032.ingest.us.sentry.io/4507360721043456",
sentry::ClientOptions {
release: sentry::release_name!(),
environment: Some(environment.clone().into()),
traces_sample_rate: 1.0,
..Default::default()
}
)))
} else {
None
};
tracing_subscriber::registry()
.with(
@ -67,6 +78,7 @@ async fn main() {
let (shutdown_tx, _) = broadcast::channel::<()>(1);
let shutdown_tx = Arc::new(shutdown_tx);
// Build the router with or without Sentry layers based on environment
let app = Router::new()
.merge(protected_router)
.merge(public_router)
@ -75,6 +87,17 @@ async fn main() {
.layer(CompressionLayer::new())
.layer(Extension(shutdown_tx.clone()));
// Add Sentry layers if not in development
let app = if !is_development {
app.layer(
ServiceBuilder::new()
.layer(sentry_tower::NewSentryLayer::<Request>::new_from_top())
.layer(sentry_tower::SentryHttpLayer::with_transaction())
)
} else {
app
};
let port_number: u16 = env::var("PORT")
.unwrap_or_else(|_| "3001".to_string())
.parse()

View File

@ -7,7 +7,7 @@ use handlers::organizations::{
update_organization_handler,
};
use crate::{routes::rest::ApiResponse, utils::clients::sentry_utils::send_sentry_error};
use crate::routes::rest::ApiResponse;
use middleware::AuthenticatedUser;
pub async fn update_organization(
@ -27,7 +27,6 @@ pub async fn update_organization(
Ok(organization) => organization,
Err(e) => {
tracing::error!("Error updating organization: {:?}", e);
send_sentry_error(&e.to_string(), Some(&user.id));
if e.to_string().contains("not a workspace admin") {
return Err((StatusCode::FORBIDDEN, "User is not a workspace admin"));

View File

@ -11,7 +11,7 @@ use database::{
schema::{users, users_to_organizations},
};
use crate::{routes::rest::ApiResponse, utils::clients::sentry_utils::send_sentry_error};
use crate::routes::rest::ApiResponse;
use middleware::AuthenticatedUser;
#[derive(Serialize, Deserialize, Clone)]
@ -31,7 +31,6 @@ pub async fn list_organization_users(
Ok(users) => users,
Err(e) => {
tracing::error!("Error listing organization users: {:?}", e);
send_sentry_error(&e.to_string(), Some(&user.id));
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
"Error listing organization users",

View File

@ -9,7 +9,6 @@ use database::schema::{
organizations, teams, teams_to_users, users, users_to_organizations,
};
use crate::routes::rest::ApiResponse;
use crate::utils::clients::sentry_utils::send_sentry_error;
use axum::http::StatusCode;
use diesel::{
BoolExpressionMethods, ExpressionMethods, JoinOnDsl, NullableExpressionMethods, QueryDsl,
@ -25,7 +24,6 @@ pub async fn get_user(
Ok(user_info_object) => user_info_object,
Err(e) => {
tracing::error!("Error getting user information: {:?}", e);
send_sentry_error(&e.to_string(), Some(&user.id));
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
"Error getting user information",

View File

@ -13,7 +13,7 @@ use database::{
},
};
use crate::{routes::rest::ApiResponse, utils::clients::sentry_utils::send_sentry_error};
use crate::routes::rest::ApiResponse;
use axum::http::StatusCode;
use diesel::{
BoolExpressionMethods, ExpressionMethods, JoinOnDsl, NullableExpressionMethods, QueryDsl,
@ -54,7 +54,6 @@ pub async fn get_user_by_id(
Ok(user_info) => user_info,
Err(e) => {
tracing::error!("Error getting user information: {:?}", e);
send_sentry_error(&e.to_string(), Some(&user.id));
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
"Error getting user information",

View File

@ -2,19 +2,18 @@ use anyhow::Result;
use axum::extract::Path;
use axum::{Extension, Json};
use crate::routes::rest::ApiResponse;
use crate::utils::security::checks::is_user_workspace_admin_or_data_admin;
use axum::http::StatusCode;
use database::enums::UserOrganizationStatus;
use database::organization::get_user_organization_id;
use database::schema::{users, users_to_organizations};
use database::{enums::UserOrganizationRole, pool::get_pg_pool};
use crate::routes::rest::ApiResponse;
use crate::utils::clients::sentry_utils::send_sentry_error;
use crate::utils::security::checks::is_user_workspace_admin_or_data_admin;
use database::organization::get_user_organization_id;
use axum::http::StatusCode;
use diesel::{update, ExpressionMethods};
use diesel_async::RunQueryDsl;
use middleware::AuthenticatedUser;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use middleware::AuthenticatedUser;
#[derive(Serialize, Deserialize, Clone)]
pub struct UserResponse {
@ -40,7 +39,6 @@ pub async fn update_user(
Ok(_) => (),
Err(e) => {
tracing::error!("Error getting user information: {:?}", e);
send_sentry_error(&e.to_string(), Some(&user.id));
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
"Error getting user information",
@ -120,7 +118,7 @@ pub async fn update_user_handler(
))
}
};
},
}
Ok(false) => return Err(anyhow::anyhow!("Insufficient permissions to update role")),
Err(e) => {
tracing::error!("Error checking user permissions for role update: {:?}", e);

View File

@ -5,8 +5,6 @@ use html_escape::encode_text as escape_html;
use resend_rs::{types::CreateEmailBaseOptions, Resend};
use crate::utils::clients::sentry_utils::send_sentry_error;
lazy_static::lazy_static! {
static ref RESEND_API_KEY: String = env::var("RESEND_API_KEY").expect("RESEND_API_KEY must be set");
static ref RESEND_CLIENT: Resend = Resend::new(&RESEND_API_KEY);
@ -86,7 +84,6 @@ pub async fn send_email(to_addresses: HashSet<String>, email_type: EmailType) ->
Ok(_) => (),
Err(e) => {
tracing::error!("Error sending email: {e}");
send_sentry_error(&format!("Error sending email: {e}"), None)
}
}
});

View File

@ -1,2 +1 @@
pub mod email;
pub mod sentry_utils;

View File

@ -1,24 +0,0 @@
use std::time::SystemTime;
use sentry::{capture_event, protocol::Event, User};
use uuid::Uuid;
pub fn send_sentry_error(message: &String, user_id: Option<&Uuid>) {
let user: Option<User> = match user_id {
Some(id) => Some(User {
id: Some(id.to_string()),
..Default::default()
}),
None => None,
};
let event = Event {
message: Some(message.to_string()),
level: sentry::Level::Error,
event_id: Uuid::new_v4(),
timestamp: SystemTime::now(),
user,
..Default::default()
};
capture_event(event);
}