mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-07 20:39:04 +03:00
assistant2: List saved conversations from disk (#11627)
This PR updates the saved conversation picker to use a list of conversations retrieved from disk instead of the static placeholder values. Release Notes: - N/A
This commit is contained in:
parent
8b5a0cff10
commit
c73ef1a5f3
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -377,6 +377,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"assets",
|
||||
"assistant_tooling",
|
||||
"chrono",
|
||||
"client",
|
||||
"collections",
|
||||
"editor",
|
||||
@ -395,6 +396,7 @@ dependencies = [
|
||||
"picker",
|
||||
"project",
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
"release_channel",
|
||||
"rich_text",
|
||||
"schemars",
|
||||
|
@ -19,6 +19,7 @@ stories = ["dep:story"]
|
||||
anyhow.workspace = true
|
||||
assistant_tooling.workspace = true
|
||||
client.workspace = true
|
||||
chrono.workspace = true
|
||||
collections.workspace = true
|
||||
editor.workspace = true
|
||||
feature_flags.workspace = true
|
||||
@ -32,6 +33,7 @@ nanoid.workspace = true
|
||||
open_ai.workspace = true
|
||||
picker.workspace = true
|
||||
project.workspace = true
|
||||
regex.workspace = true
|
||||
rich_text.workspace = true
|
||||
schemars.workspace = true
|
||||
semantic_index.workspace = true
|
||||
|
@ -1,6 +1,16 @@
|
||||
use std::cmp::Reverse;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Result;
|
||||
use assistant_tooling::{SavedToolFunctionCall, SavedUserAttachment};
|
||||
use fs::Fs;
|
||||
use futures::StreamExt;
|
||||
use gpui::SharedString;
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use util::paths::CONVERSATIONS_DIR;
|
||||
|
||||
use crate::MessageId;
|
||||
|
||||
@ -33,25 +43,48 @@ pub struct SavedAssistantMessagePart {
|
||||
pub tool_calls: Vec<SavedToolFunctionCall>,
|
||||
}
|
||||
|
||||
/// Returns a list of placeholder conversations for mocking the UI.
|
||||
///
|
||||
/// Once we have real saved conversations to pull from we can use those instead.
|
||||
pub fn placeholder_conversations() -> Vec<SavedConversation> {
|
||||
vec![
|
||||
SavedConversation {
|
||||
version: "0.3.0".to_string(),
|
||||
title: "How to get a list of exported functions in an Erlang module".to_string(),
|
||||
messages: vec![],
|
||||
},
|
||||
SavedConversation {
|
||||
version: "0.3.0".to_string(),
|
||||
title: "7 wonders of the ancient world".to_string(),
|
||||
messages: vec![],
|
||||
},
|
||||
SavedConversation {
|
||||
version: "0.3.0".to_string(),
|
||||
title: "Size difference between u8 and a reference to u8 in Rust".to_string(),
|
||||
messages: vec![],
|
||||
},
|
||||
]
|
||||
pub struct SavedConversationMetadata {
|
||||
pub title: String,
|
||||
pub path: PathBuf,
|
||||
pub mtime: chrono::DateTime<chrono::Local>,
|
||||
}
|
||||
|
||||
impl SavedConversationMetadata {
|
||||
pub async fn list(fs: Arc<dyn Fs>) -> Result<Vec<Self>> {
|
||||
fs.create_dir(&CONVERSATIONS_DIR).await?;
|
||||
|
||||
let mut paths = fs.read_dir(&CONVERSATIONS_DIR).await?;
|
||||
let mut conversations = Vec::new();
|
||||
while let Some(path) = paths.next().await {
|
||||
let path = path?;
|
||||
if path.extension() != Some(OsStr::new("json")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let pattern = r" - \d+.zed.\d.\d.\d.json$";
|
||||
let re = Regex::new(pattern).unwrap();
|
||||
|
||||
let metadata = fs.metadata(&path).await?;
|
||||
if let Some((file_name, metadata)) = path
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.zip(metadata)
|
||||
{
|
||||
// This is used to filter out conversations saved by the old assistant.
|
||||
if !re.is_match(file_name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let title = re.replace(file_name, "");
|
||||
conversations.push(Self {
|
||||
title: title.into_owned(),
|
||||
path,
|
||||
mtime: metadata.mtime.into(),
|
||||
});
|
||||
}
|
||||
}
|
||||
conversations.sort_unstable_by_key(|conversation| Reverse(conversation.mtime));
|
||||
|
||||
Ok(conversations)
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use ui::{prelude::*, HighlightedLabel, ListItem, ListItemSpacing};
|
||||
use util::ResultExt;
|
||||
use workspace::{ModalView, Workspace};
|
||||
|
||||
use crate::saved_conversation::{self, SavedConversation};
|
||||
use crate::saved_conversation::SavedConversationMetadata;
|
||||
use crate::ToggleSavedConversations;
|
||||
|
||||
pub struct SavedConversationPicker {
|
||||
@ -27,10 +27,26 @@ impl FocusableView for SavedConversationPicker {
|
||||
impl SavedConversationPicker {
|
||||
pub fn register(workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>) {
|
||||
workspace.register_action(|workspace, _: &ToggleSavedConversations, cx| {
|
||||
workspace.toggle_modal(cx, move |cx| {
|
||||
let delegate = SavedConversationPickerDelegate::new(cx.view().downgrade());
|
||||
Self::new(delegate, cx)
|
||||
});
|
||||
let fs = workspace.project().read(cx).fs().clone();
|
||||
|
||||
cx.spawn(|workspace, mut cx| async move {
|
||||
let saved_conversations = SavedConversationMetadata::list(fs).await?;
|
||||
|
||||
cx.update(|cx| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace.toggle_modal(cx, move |cx| {
|
||||
let delegate = SavedConversationPickerDelegate::new(
|
||||
cx.view().downgrade(),
|
||||
saved_conversations,
|
||||
);
|
||||
Self::new(delegate, cx)
|
||||
});
|
||||
})
|
||||
})??;
|
||||
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
});
|
||||
}
|
||||
|
||||
@ -48,14 +64,16 @@ impl Render for SavedConversationPicker {
|
||||
|
||||
pub struct SavedConversationPickerDelegate {
|
||||
view: WeakView<SavedConversationPicker>,
|
||||
saved_conversations: Vec<SavedConversation>,
|
||||
saved_conversations: Vec<SavedConversationMetadata>,
|
||||
selected_index: usize,
|
||||
matches: Vec<StringMatch>,
|
||||
}
|
||||
|
||||
impl SavedConversationPickerDelegate {
|
||||
pub fn new(weak_view: WeakView<SavedConversationPicker>) -> Self {
|
||||
let saved_conversations = saved_conversation::placeholder_conversations();
|
||||
pub fn new(
|
||||
weak_view: WeakView<SavedConversationPicker>,
|
||||
saved_conversations: Vec<SavedConversationMetadata>,
|
||||
) -> Self {
|
||||
let matches = saved_conversations
|
||||
.iter()
|
||||
.map(|conversation| StringMatch {
|
||||
|
Loading…
Reference in New Issue
Block a user