* feat: improve mental models ux on control plane * feat: improve mental models ux on control plane * gen * feat(cli): add --id flag to mental model create command * fix(cli): revert unused variable underscore prefix that breaks compilation The underscore prefix on stdout/stderr variables was added to suppress warnings, but these variables are actually used in assert messages, causing compilation errors. Reverting to original names.
287 lines
7.7 KiB
Rust
287 lines
7.7 KiB
Rust
//! Mental model commands for managing user-curated summaries.
|
|
|
|
use anyhow::Result;
|
|
|
|
use crate::api::ApiClient;
|
|
use crate::output::{self, OutputFormat};
|
|
use crate::ui;
|
|
|
|
use hindsight_client::types;
|
|
|
|
/// List mental models for a bank
|
|
pub fn list(
|
|
client: &ApiClient,
|
|
bank_id: &str,
|
|
verbose: bool,
|
|
output_format: OutputFormat,
|
|
) -> Result<()> {
|
|
let spinner = if output_format == OutputFormat::Pretty {
|
|
Some(ui::create_spinner("Fetching mental models..."))
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let response = client.list_mental_models(bank_id, verbose);
|
|
|
|
if let Some(mut sp) = spinner {
|
|
sp.finish();
|
|
}
|
|
|
|
match response {
|
|
Ok(result) => {
|
|
if output_format == OutputFormat::Pretty {
|
|
ui::print_section_header(&format!("Mental Models: {}", bank_id));
|
|
|
|
if result.items.is_empty() {
|
|
println!(" {}", ui::dim("No mental models found."));
|
|
} else {
|
|
for mental_model in &result.items {
|
|
println!(
|
|
" {} {}",
|
|
ui::gradient_start(&mental_model.id),
|
|
mental_model.name
|
|
);
|
|
|
|
// Show content preview
|
|
let preview: String = mental_model.content.chars().take(80).collect();
|
|
let ellipsis = if mental_model.content.len() > 80 { "..." } else { "" };
|
|
println!(" {}{}", ui::dim(&preview), ellipsis);
|
|
|
|
println!();
|
|
}
|
|
}
|
|
} else {
|
|
output::print_output(&result, output_format)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
Err(e) => Err(e),
|
|
}
|
|
}
|
|
|
|
/// Get a specific mental model
|
|
pub fn get(
|
|
client: &ApiClient,
|
|
bank_id: &str,
|
|
mental_model_id: &str,
|
|
verbose: bool,
|
|
output_format: OutputFormat,
|
|
) -> Result<()> {
|
|
let spinner = if output_format == OutputFormat::Pretty {
|
|
Some(ui::create_spinner("Fetching mental model..."))
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let response = client.get_mental_model(bank_id, mental_model_id, verbose);
|
|
|
|
if let Some(mut sp) = spinner {
|
|
sp.finish();
|
|
}
|
|
|
|
match response {
|
|
Ok(mental_model) => {
|
|
if output_format == OutputFormat::Pretty {
|
|
print_mental_model_detail(&mental_model);
|
|
} else {
|
|
output::print_output(&mental_model, output_format)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
Err(e) => Err(e),
|
|
}
|
|
}
|
|
|
|
/// Create a new mental model
|
|
pub fn create(
|
|
client: &ApiClient,
|
|
bank_id: &str,
|
|
name: &str,
|
|
source_query: &str,
|
|
id: Option<&str>,
|
|
verbose: bool,
|
|
output_format: OutputFormat,
|
|
) -> Result<()> {
|
|
let spinner = if output_format == OutputFormat::Pretty {
|
|
Some(ui::create_spinner("Creating mental model..."))
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let request = types::CreateMentalModelRequest {
|
|
id: id.map(|s| s.to_string()),
|
|
name: name.to_string(),
|
|
source_query: source_query.to_string(),
|
|
max_tokens: 2048,
|
|
tags: vec![],
|
|
trigger: None,
|
|
};
|
|
|
|
let response = client.create_mental_model(bank_id, &request, verbose);
|
|
|
|
if let Some(mut sp) = spinner {
|
|
sp.finish();
|
|
}
|
|
|
|
match response {
|
|
Ok(result) => {
|
|
if output_format == OutputFormat::Pretty {
|
|
ui::print_success(&format!("Mental model created, operation_id: {}", result.operation_id));
|
|
} else {
|
|
output::print_output(&result, output_format)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
Err(e) => Err(e),
|
|
}
|
|
}
|
|
|
|
/// Update a mental model
|
|
pub fn update(
|
|
client: &ApiClient,
|
|
bank_id: &str,
|
|
mental_model_id: &str,
|
|
name: Option<String>,
|
|
verbose: bool,
|
|
output_format: OutputFormat,
|
|
) -> Result<()> {
|
|
if name.is_none() {
|
|
anyhow::bail!("--name must be provided");
|
|
}
|
|
|
|
let spinner = if output_format == OutputFormat::Pretty {
|
|
Some(ui::create_spinner("Updating mental model..."))
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let request = types::UpdateMentalModelRequest {
|
|
name,
|
|
source_query: None,
|
|
max_tokens: None,
|
|
tags: None,
|
|
trigger: None,
|
|
};
|
|
|
|
let response = client.update_mental_model(bank_id, mental_model_id, &request, verbose);
|
|
|
|
if let Some(mut sp) = spinner {
|
|
sp.finish();
|
|
}
|
|
|
|
match response {
|
|
Ok(mental_model) => {
|
|
if output_format == OutputFormat::Pretty {
|
|
ui::print_success(&format!("Mental model '{}' updated successfully", mental_model_id));
|
|
println!();
|
|
print_mental_model_detail(&mental_model);
|
|
} else {
|
|
output::print_output(&mental_model, output_format)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
Err(e) => Err(e),
|
|
}
|
|
}
|
|
|
|
/// Delete a mental model
|
|
pub fn delete(
|
|
client: &ApiClient,
|
|
bank_id: &str,
|
|
mental_model_id: &str,
|
|
yes: bool,
|
|
verbose: bool,
|
|
output_format: OutputFormat,
|
|
) -> Result<()> {
|
|
// Confirmation prompt unless -y flag is used
|
|
if !yes && output_format == OutputFormat::Pretty {
|
|
let message = format!(
|
|
"Are you sure you want to delete mental model '{}'? This cannot be undone.",
|
|
mental_model_id
|
|
);
|
|
|
|
let confirmed = ui::prompt_confirmation(&message)?;
|
|
|
|
if !confirmed {
|
|
ui::print_info("Operation cancelled");
|
|
return Ok(());
|
|
}
|
|
}
|
|
|
|
let spinner = if output_format == OutputFormat::Pretty {
|
|
Some(ui::create_spinner("Deleting mental model..."))
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let response = client.delete_mental_model(bank_id, mental_model_id, verbose);
|
|
|
|
if let Some(mut sp) = spinner {
|
|
sp.finish();
|
|
}
|
|
|
|
match response {
|
|
Ok(_) => {
|
|
if output_format == OutputFormat::Pretty {
|
|
ui::print_success(&format!("Mental model '{}' deleted successfully", mental_model_id));
|
|
} else {
|
|
println!("{{\"success\": true}}");
|
|
}
|
|
Ok(())
|
|
}
|
|
Err(e) => Err(e),
|
|
}
|
|
}
|
|
|
|
/// Refresh a mental model
|
|
pub fn refresh(
|
|
client: &ApiClient,
|
|
bank_id: &str,
|
|
mental_model_id: &str,
|
|
verbose: bool,
|
|
output_format: OutputFormat,
|
|
) -> Result<()> {
|
|
let spinner = if output_format == OutputFormat::Pretty {
|
|
Some(ui::create_spinner("Submitting mental model refresh..."))
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let response = client.refresh_mental_model(bank_id, mental_model_id, verbose);
|
|
|
|
if let Some(mut sp) = spinner {
|
|
sp.finish();
|
|
}
|
|
|
|
match response {
|
|
Ok(operation) => {
|
|
if output_format == OutputFormat::Pretty {
|
|
ui::print_success(&format!(
|
|
"Mental model refresh submitted. Operation ID: {}",
|
|
operation.operation_id
|
|
));
|
|
println!(" {} {}", ui::dim("Status:"), operation.status);
|
|
println!();
|
|
println!("{}", ui::dim("Use 'hindsight operations get' to check the operation status."));
|
|
} else {
|
|
output::print_output(&operation, output_format)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
Err(e) => Err(e),
|
|
}
|
|
}
|
|
|
|
// Helper function to print mental model details
|
|
fn print_mental_model_detail(mental_model: &types::MentalModelResponse) {
|
|
ui::print_section_header(&mental_model.name);
|
|
|
|
println!(" {} {}", ui::dim("ID:"), ui::gradient_start(&mental_model.id));
|
|
println!(" {} {}", ui::dim("Source Query:"), &mental_model.source_query);
|
|
|
|
println!();
|
|
println!("{}", ui::gradient_text("─── Content ───"));
|
|
println!();
|
|
println!("{}", &mental_model.content);
|
|
println!();
|
|
}
|