feat: `save_session` config item can be null (#380)

pull/381/head
sigoden 2 months ago committed by GitHub
parent a05c462531
commit bd9a6a8725
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -82,7 +82,7 @@ Feel free to adjust the configuration according to your needs.
model: openai:gpt-3.5-turbo # LLM model
temperature: 1.0 # LLM temperature
save: true # Whether to save the message
save_session: false # Whether to save the session automatically
save_session: null # Whether to save the session, if null, asking
highlight: true # Set false to turn highlight
light_theme: false # Whether to use a light theme
wrap: no # Specify the text-wrapping mode (no, auto, <max-width>)

@ -1,7 +1,7 @@
model: openai:gpt-3.5-turbo # LLM model
temperature: 1.0 # LLM temperature
save: true # Whether to save the message
save_session: false # Whether to save the session automatically
save_session: null # Whether to save the session, if null, asking
highlight: true # Set false to turn highlight
light_theme: false # Whether to use a light theme
wrap: no # Specify the text-wrapping mode (no, auto, <max-width>)

@ -12,7 +12,7 @@ pub struct Cli {
/// Create or reuse a session
#[clap(short = 's', long)]
pub session: Option<Option<String>>,
/// Whether to save the session automatically
/// Whether to save the session
#[clap(long)]
pub save_session: bool,
/// Execute commands using natural language

@ -52,8 +52,8 @@ pub struct Config {
pub dry_run: bool,
/// Whether to save the message
pub save: bool,
/// Whether to save the session automatically
pub save_session: bool,
/// Whether to save the session
pub save_session: Option<bool>,
/// Whether to disable highlight
pub highlight: bool,
/// Whether to use a light theme
@ -101,6 +101,7 @@ impl Default for Config {
model_id: None,
temperature: None,
save: true,
save_session: None,
highlight: true,
dry_run: false,
light_theme: false,
@ -109,7 +110,6 @@ impl Default for Config {
auto_copy: false,
keybindings: Default::default(),
prelude: String::new(),
save_session: false,
compress_threshold: 2000,
summarize_prompt: "Summarize the discussion briefly in 200 words or less to use as a prompt for future context.".to_string(),
summary_prompt: "This is a summary of the chat history as a recap: ".into(),
@ -353,7 +353,7 @@ impl Config {
}
}
pub fn set_save_session(&mut self, value: bool) {
pub fn set_save_session(&mut self, value: Option<bool>) {
if let Some(session) = self.session.as_mut() {
session.set_save_session(value);
} else {
@ -422,9 +422,6 @@ impl Config {
pub fn sys_info(&self) -> Result<String> {
let display_path = |path: &Path| path.display().to_string();
let temperature = self
.temperature
.map_or_else(|| String::from("-"), |v| v.to_string());
let wrap = self
.wrap
.clone()
@ -436,10 +433,10 @@ impl Config {
};
let items = vec![
("model", self.model.id()),
("temperature", temperature),
("temperature", format_option(&self.temperature)),
("dry_run", self.dry_run.to_string()),
("save", self.save.to_string()),
("save_session", self.save_session.to_string()),
("save_session", format_option(&self.save_session)),
("highlight", self.highlight.to_string()),
("light_theme", self.light_theme.to_string()),
("wrap", wrap),
@ -518,19 +515,19 @@ impl Config {
};
(values, args[0])
} else if args.len() == 2 {
let to_vec = |v: bool| vec![v.to_string()];
let values = match args[0] {
"save" => to_vec(!self.save),
"save" => complete_bool(self.save),
"save_session" => {
if let Some(session) = &self.session {
to_vec(!session.save_session())
let save_session = if let Some(session) = &self.session {
session.save_session()
} else {
to_vec(!self.save_session)
}
self.save_session
};
complete_option_bool(save_session)
}
"highlight" => to_vec(!self.highlight),
"dry_run" => to_vec(!self.dry_run),
"auto_copy" => to_vec(!self.auto_copy),
"highlight" => complete_bool(self.highlight),
"dry_run" => complete_bool(self.dry_run),
"auto_copy" => complete_bool(self.auto_copy),
_ => vec![],
};
(values, args[1])
@ -550,24 +547,13 @@ impl Config {
}
let key = parts[0];
let value = parts[1];
let unset = value == "null";
match key {
"temperature" => {
let value = if unset {
None
} else {
let value = value.parse().with_context(|| "Invalid value")?;
Some(value)
};
let value = parse_value(value)?;
self.set_temperature(value);
}
"compress_threshold" => {
let value = if unset {
None
} else {
let value = value.parse().with_context(|| "Invalid value")?;
Some(value)
};
let value = parse_value(value)?;
self.set_compress_threshold(value);
}
"save" => {
@ -575,7 +561,7 @@ impl Config {
self.save = value;
}
"save_session" => {
let value = value.parse().with_context(|| "Invalid value")?;
let value = parse_value(value)?;
self.set_save_session(value);
}
"highlight" => {
@ -609,7 +595,9 @@ impl Config {
format!("Failed to cleanup previous '{TEMP_SESSION_NAME}' session")
})?;
}
self.session = Some(Session::new(self, TEMP_SESSION_NAME));
let mut session = Session::new(self, TEMP_SESSION_NAME);
session.set_save_session(None);
self.session = Some(session);
}
Some(name) => {
let session_path = Self::session_file(name)?;
@ -645,10 +633,9 @@ impl Config {
pub fn end_session(&mut self, interactive: bool) -> Result<()> {
if let Some(mut session) = self.session.take() {
self.last_message = None;
if session.dirty {
// If it's a temporary session, we'll always prompt to save on exit
// If it's named, we'll save automatically if they've set the save flag and prompt if they haven't
if !session.save_session() || session.is_temp() {
let save_session = session.save_session();
if session.dirty && save_session != Some(false) {
if save_session.is_none() {
if !interactive {
// If we're not interactive, we will not prompt and will not save
return Ok(());
@ -842,6 +829,7 @@ impl Config {
}
if let Some(session) = &self.session {
output.insert("session", session.name().to_string());
output.insert("dirty", session.dirty.to_string());
let (tokens, percent) = session.tokens_and_percent();
output.insert("consume_tokens", tokens.to_string());
output.insert("consume_percent", percent.to_string());
@ -1124,6 +1112,44 @@ fn set_bool(target: &mut bool, value: &str) {
}
}
fn parse_value<T>(value: &str) -> Result<Option<T>>
where
T: std::str::FromStr,
{
let value = if value == "null" {
None
} else {
let value = match value.parse() {
Ok(value) => value,
Err(_) => bail!("Invalid value '{}'", value),
};
Some(value)
};
Ok(value)
}
fn format_option<T>(value: &Option<T>) -> String
where
T: std::fmt::Display,
{
match value {
Some(value) => value.to_string(),
None => "-".to_string(),
}
}
fn complete_bool(value: bool) -> Vec<String> {
vec![(!value).to_string()]
}
fn complete_option_bool(value: Option<bool>) -> Vec<String> {
match value {
Some(true) => vec!["false".to_string(), "null".to_string()],
Some(false) => vec!["true".to_string(), "null".to_string()],
None => vec!["true".to_string(), "false".to_string()],
}
}
#[cfg(debug_assertions)]
fn setup_logger() -> Result<()> {
use simplelog::{LevelFilter, WriteLogger};

@ -19,7 +19,7 @@ pub struct Session {
model_id: String,
temperature: Option<f64>,
#[serde(default)]
save_session: bool,
save_session: Option<bool>,
messages: Vec<Message>,
#[serde(default)]
data_urls: HashMap<String, String>,
@ -80,7 +80,7 @@ impl Session {
self.temperature
}
pub fn save_session(&self) -> bool {
pub fn save_session(&self) -> Option<bool> {
self.save_session
}
@ -100,7 +100,9 @@ impl Session {
}
pub fn export(&self) -> Result<String> {
self.guard_save()?;
if self.path.is_none() {
bail!("Not found session '{}'", self.name)
}
let (tokens, percent) = self.tokens_and_percent();
let mut data = json!({
"path": self.path,
@ -109,7 +111,9 @@ impl Session {
if let Some(temperature) = self.temperature() {
data["temperature"] = temperature.into();
}
data["save_session"] = self.save_session.into();
if let Some(save_session) = self.save_session() {
data["save_session"] = save_session.into();
}
data["total_tokens"] = tokens.into();
if let Some(conext_window) = self.model.max_input_tokens {
data["max_input_tokens"] = conext_window.into();
@ -137,7 +141,9 @@ impl Session {
items.push(("temperature", temperature.to_string()));
}
items.push(("save_session", self.save_session.to_string()));
if let Some(save_session) = self.save_session() {
items.push(("save_session", save_session.to_string()));
}
if let Some(compress_threshold) = self.compress_threshold {
items.push(("compress_threshold", compress_threshold.to_string()));
@ -201,7 +207,7 @@ impl Session {
}
}
pub fn set_save_session(&mut self, value: bool) {
pub fn set_save_session(&mut self, value: Option<bool>) {
if self.save_session != value {
self.save_session = value;
self.dirty = true;
@ -255,13 +261,6 @@ impl Session {
Ok(())
}
pub fn guard_save(&self) -> Result<()> {
if self.path.is_none() {
bail!("Not found session '{}'", self.name)
}
Ok(())
}
pub fn guard_empty(&self) -> Result<()> {
if !self.is_empty() {
bail!("Cannot perform this action in a session with messages")

@ -76,7 +76,7 @@ fn main() -> Result<()> {
config.write().set_model(model)?;
}
if cli.save_session {
config.write().set_save_session(true);
config.write().set_save_session(Some(true));
}
if cli.no_highlight {
config.write().highlight = false;

Loading…
Cancel
Save