
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
90 lines
2.5 KiB
Rust
90 lines
2.5 KiB
Rust
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;
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct SavedConversation {
|
|
/// The schema version of the conversation.
|
|
pub version: String,
|
|
/// The title of the conversation, generated by the Assistant.
|
|
pub title: String,
|
|
pub messages: Vec<SavedChatMessage>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub enum SavedChatMessage {
|
|
User {
|
|
id: MessageId,
|
|
body: String,
|
|
attachments: Vec<SavedUserAttachment>,
|
|
},
|
|
Assistant {
|
|
id: MessageId,
|
|
messages: Vec<SavedAssistantMessagePart>,
|
|
error: Option<SharedString>,
|
|
},
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct SavedAssistantMessagePart {
|
|
pub body: SharedString,
|
|
pub tool_calls: Vec<SavedToolFunctionCall>,
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|