modify files going good

This commit is contained in:
dal 2025-04-04 09:44:10 -06:00
parent fddc909f0f
commit 38f1c9c54c
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
8 changed files with 56 additions and 18 deletions

View File

@ -442,6 +442,7 @@ definitions:
metric_value_aggregate: metric_value_aggregate:
type: string type: string
enum: ["sum", "average", "median", "max", "min", "count", "first"] enum: ["sum", "average", "median", "max", "min", "count", "first"]
description: "Optional - only used when the user specifically requests it, otherwise leave blank"
required: required:
- selected_chart_type - selected_chart_type
- metric_column_id - metric_column_id

View File

@ -261,6 +261,7 @@ impl ToolExecutor for CreateDashboardFilesTool {
results: None, results: None,
created_at: dashboard_records[i].created_at, created_at: dashboard_records[i].created_at,
updated_at: dashboard_records[i].updated_at, updated_at: dashboard_records[i].updated_at,
version_number: dashboard_records[i].version_history.get_version_number(),
}); });
} }
} }

View File

@ -176,6 +176,7 @@ impl ToolExecutor for CreateMetricFilesTool {
results: Some(results_vec[i].1.clone()), results: Some(results_vec[i].1.clone()),
created_at: metric_records[i].created_at, created_at: metric_records[i].created_at,
updated_at: metric_records[i].updated_at, updated_at: metric_records[i].updated_at,
version_number: metric_records[i].version_history.get_version_number(),
}); });
} }
} }

View File

@ -24,6 +24,7 @@ pub struct FileWithId {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub results: Option<Vec<IndexMap<String, DataType>>>, pub results: Option<Vec<IndexMap<String, DataType>>>,
pub created_at: DateTime<Utc>, pub created_at: DateTime<Utc>,
pub version_number: i32,
pub updated_at: DateTime<Utc>, pub updated_at: DateTime<Utc>,
} }

View File

@ -1,5 +1,5 @@
use std::{env, sync::Arc};
use std::time::Instant; use std::time::Instant;
use std::{env, sync::Arc};
use anyhow::Result; use anyhow::Result;
use async_trait::async_trait; use async_trait::async_trait;
@ -16,8 +16,8 @@ use tracing::{debug, error, info};
use super::{ use super::{
common::{ common::{
ModificationResult, process_dashboard_file_modification, ModificationResult, ModifyFilesOutput,
ModifyFilesOutput, ModifyFilesParams, process_dashboard_file_modification, ModifyFilesParams,
}, },
file_types::file::FileWithId, file_types::file::FileWithId,
FileModificationTool, FileModificationTool,
@ -59,10 +59,13 @@ impl ToolExecutor for ModifyDashboardFilesTool {
} }
async fn is_enabled(&self) -> bool { async fn is_enabled(&self) -> bool {
matches!(( matches!(
self.agent.get_state_value("dashboards_available").await, (
self.agent.get_state_value("plan_available").await, self.agent.get_state_value("dashboards_available").await,
), (Some(_), Some(_))) self.agent.get_state_value("plan_available").await,
),
(Some(_), Some(_))
)
} }
async fn execute(&self, params: Self::Params, _tool_call_id: String) -> Result<Self::Output> { async fn execute(&self, params: Self::Params, _tool_call_id: String) -> Result<Self::Output> {
@ -99,19 +102,35 @@ impl ToolExecutor for ModifyDashboardFilesTool {
// Process the dashboard file modification // Process the dashboard file modification
match process_dashboard_file_modification( match process_dashboard_file_modification(
dashboard_file, dashboard_file.clone(),
&modification, &modification,
duration, duration,
) )
.await .await
{ {
Ok(( Ok((
dashboard_file, mut dashboard_file,
dashboard_yml, dashboard_yml,
results, results,
validation_message, validation_message,
validation_results, validation_results,
)) => { )) => {
// Calculate next version number from existing version history
let next_version =
match dashboard_file.version_history.get_latest_version() {
Some(version) => version.version_number + 1,
None => 1,
};
// Add new version to history
dashboard_file
.version_history
.add_version(next_version, dashboard_yml.clone());
// Ensure the name field is updated
// This is redundant but ensures the name is set correctly
dashboard_file.name = dashboard_yml.name.clone();
batch.files.push(dashboard_file); batch.files.push(dashboard_file);
batch.ymls.push(dashboard_yml); batch.ymls.push(dashboard_yml);
batch.modification_results.extend(results); batch.modification_results.extend(results);
@ -134,7 +153,7 @@ impl ToolExecutor for ModifyDashboardFilesTool {
} }
} }
// Update dashboard files in database // Update dashboard files in database with version history
if !batch.files.is_empty() { if !batch.files.is_empty() {
use diesel::insert_into; use diesel::insert_into;
match insert_into(dashboard_files::table) match insert_into(dashboard_files::table)
@ -144,12 +163,16 @@ impl ToolExecutor for ModifyDashboardFilesTool {
.set(( .set((
dashboard_files::content.eq(excluded(dashboard_files::content)), dashboard_files::content.eq(excluded(dashboard_files::content)),
dashboard_files::updated_at.eq(excluded(dashboard_files::updated_at)), dashboard_files::updated_at.eq(excluded(dashboard_files::updated_at)),
// Add version history and name to ensure they're updated
dashboard_files::version_history.eq(excluded(dashboard_files::version_history)),
// Explicitly set name even though it's in content to ensure it's updated in case content parsing fails
dashboard_files::name.eq(excluded(dashboard_files::name)),
)) ))
.execute(&mut conn) .execute(&mut conn)
.await .await
{ {
Ok(_) => { Ok(_) => {
debug!("Successfully updated dashboard files in database"); debug!("Successfully updated dashboard files with versioning");
} }
Err(e) => { Err(e) => {
error!("Failed to update dashboard files in database: {}", e); error!("Failed to update dashboard files in database: {}", e);
@ -164,7 +187,10 @@ impl ToolExecutor for ModifyDashboardFilesTool {
// Generate output // Generate output
let duration = start_time.elapsed().as_millis() as i64; let duration = start_time.elapsed().as_millis() as i64;
let mut output = ModifyFilesOutput { let mut output = ModifyFilesOutput {
message: format!("Modified {} dashboard files", batch.files.len()), message: format!(
"Modified {} dashboard files and created new versions",
batch.files.len()
),
duration, duration,
files: Vec::new(), files: Vec::new(),
}; };
@ -183,6 +209,7 @@ impl ToolExecutor for ModifyDashboardFilesTool {
results: Some(batch.validation_results[i].clone()), results: Some(batch.validation_results[i].clone()),
created_at: file.created_at, created_at: file.created_at,
updated_at: file.updated_at, updated_at: file.updated_at,
version_number: file.version_history.get_version_number(),
} }
})); }));
@ -335,7 +362,8 @@ async fn get_modify_dashboards_new_content_description() -> String {
async fn get_modify_dashboards_content_to_replace_description() -> String { async fn get_modify_dashboards_content_to_replace_description() -> String {
if env::var("USE_BRAINTRUST_PROMPTS").is_err() { if env::var("USE_BRAINTRUST_PROMPTS").is_err() {
return "The exact content in the file that should be replaced. Must match exactly.".to_string(); return "The exact content in the file that should be replaced. Must match exactly."
.to_string();
} }
let client = BraintrustClient::new(None, "96af8b2b-cf3c-494f-9092-44eb3d5b96ff").unwrap(); let client = BraintrustClient::new(None, "96af8b2b-cf3c-494f-9092-44eb3d5b96ff").unwrap();
@ -432,7 +460,6 @@ mod tests {
#[test] #[test]
fn test_tool_parameter_validation() { fn test_tool_parameter_validation() {
// Test valid parameters // Test valid parameters
let valid_params = json!({ let valid_params = json!({
"files": [{ "files": [{

View File

@ -279,6 +279,7 @@ impl ToolExecutor for ModifyMetricFilesTool {
results: Some(batch.validation_results[i].clone()), results: Some(batch.validation_results[i].clone()),
created_at: file.created_at, created_at: file.created_at,
updated_at: file.updated_at, updated_at: file.updated_at,
version_number: file.version_history.get_version_number(),
} }
})); }));

View File

@ -74,6 +74,12 @@ impl VersionHistory {
self.0.values().max_by_key(|v| v.version_number) self.0.values().max_by_key(|v| v.version_number)
} }
pub fn get_version_number(&self) -> i32 {
self.get_latest_version()
.map(|version| version.version_number)
.unwrap_or(1)
}
/// Updates the content of the latest version without creating a new version /// Updates the content of the latest version without creating a new version
/// ///
/// This is used when we want to overwrite the current version instead of creating a new one. /// This is used when we want to overwrite the current version instead of creating a new one.

View File

@ -1298,8 +1298,8 @@ fn tool_modify_metrics(id: String, content: String) -> Result<Vec<BusterReasonin
let buster_file = BusterFile { let buster_file = BusterFile {
id: file_id.clone(), id: file_id.clone(),
file_type: "metric".to_string(), file_type: "metric".to_string(),
file_name: file.name.clone(), file_name: file.name.clone(), // Use the updated name from the file
version_number: 1, version_number: file.version_number,
status: "completed".to_string(), status: "completed".to_string(),
file: BusterFileContent { file: BusterFileContent {
text: Some(file.yml_content), text: Some(file.yml_content),