Wait until we have a summary before saving a conversation

Also, avoid collisions by adding a discriminant.

Co-Authored-By: Kyle Caverly <kyle@zed.dev>
This commit is contained in:
Nathan Sobo 2023-06-20 13:03:23 -06:00
parent c416551318
commit 9f783944a7

View file

@ -458,12 +458,6 @@ enum AssistantEvent {
StreamedCompletion, StreamedCompletion,
} }
#[derive(Clone, PartialEq, Eq)]
struct SavedConversationPath {
path: PathBuf,
had_summary: bool,
}
#[derive(Default)] #[derive(Default)]
struct Summary { struct Summary {
text: String, text: String,
@ -485,7 +479,7 @@ struct Assistant {
pending_token_count: Task<Option<()>>, pending_token_count: Task<Option<()>>,
api_key: Rc<RefCell<Option<String>>>, api_key: Rc<RefCell<Option<String>>>,
pending_save: Task<Result<()>>, pending_save: Task<Result<()>>,
path: Option<SavedConversationPath>, path: Option<PathBuf>,
_subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
} }
@ -1062,15 +1056,6 @@ impl Assistant {
if let Some(debounce) = debounce { if let Some(debounce) = debounce {
cx.background().timer(debounce).await; cx.background().timer(debounce).await;
} }
let conversation = SavedConversation {
zed: "conversation".into(),
version: "0.1".into(),
messages: this.read_with(&cx, |this, cx| {
this.messages(cx)
.map(|message| message.to_open_ai_message(this.buffer.read(cx)))
.collect()
}),
};
let (old_path, summary) = this.read_with(&cx, |this, _| { let (old_path, summary) = this.read_with(&cx, |this, _| {
let path = this.path.clone(); let path = this.path.clone();
@ -1085,53 +1070,42 @@ impl Assistant {
}; };
(path, summary) (path, summary)
}); });
let mut new_path = None;
if let Some(old_path) = old_path.as_ref() {
if old_path.had_summary || summary.is_none() {
new_path = Some(old_path.clone());
}
}
let new_path = if let Some(new_path) = new_path { if let Some(summary) = summary {
new_path let conversation = SavedConversation {
} else { zed: "conversation".into(),
let mut path = version: "0.1".into(),
CONVERSATIONS_DIR.join(summary.as_deref().unwrap_or("conversation-1")); messages: this.read_with(&cx, |this, cx| {
this.messages(cx)
.map(|message| message.to_open_ai_message(this.buffer.read(cx)))
.collect()
}),
};
while fs.is_file(&path).await { let path = if let Some(old_path) = old_path {
let file_name = path.file_name().ok_or_else(|| anyhow!("no filename"))?; old_path
let file_name = file_name.to_string_lossy(); } else {
let mut discriminant = 1;
let mut new_path;
loop {
new_path = CONVERSATIONS_DIR.join(&format!(
"{} - {}.zed.json",
summary.trim(),
discriminant
));
if fs.is_file(&new_path).await {
discriminant += 1;
} else {
break;
}
}
new_path
};
if let Some((prefix, suffix)) = file_name.rsplit_once('-') { fs.create_dir(CONVERSATIONS_DIR.as_ref()).await?;
let new_version = suffix.parse::<u32>().ok().unwrap_or(1) + 1; fs.atomic_write(path.clone(), serde_json::to_string(&conversation).unwrap())
path.set_file_name(format!("{}-{}", prefix, new_version));
};
}
SavedConversationPath {
path,
had_summary: summary.is_some(),
}
};
fs.create_dir(CONVERSATIONS_DIR.as_ref()).await?;
fs.atomic_write(
new_path.path.clone(),
serde_json::to_string(&conversation).unwrap(),
)
.await?;
this.update(&mut cx, |this, _| this.path = Some(new_path.clone()));
if let Some(old_path) = old_path {
if new_path.path != old_path.path {
fs.remove_file(
&old_path.path,
fs::RemoveOptions {
recursive: false,
ignore_if_not_exists: true,
},
)
.await?; .await?;
} this.update(&mut cx, |this, _| this.path = Some(path));
} }
Ok(()) Ok(())