assistant.rs

  1pub mod assistant_panel;
  2mod assistant_settings;
  3mod codegen;
  4mod prompts;
  5mod streaming_diff;
  6
  7use ai::providers::open_ai::Role;
  8use anyhow::Result;
  9pub use assistant_panel::AssistantPanel;
 10use assistant_settings::OpenAiModel;
 11use chrono::{DateTime, Local};
 12use collections::HashMap;
 13use fs::Fs;
 14use futures::StreamExt;
 15use gpui::{actions, AppContext, SharedString};
 16use regex::Regex;
 17use serde::{Deserialize, Serialize};
 18use std::{cmp::Reverse, ffi::OsStr, path::PathBuf, sync::Arc};
 19use util::paths::CONVERSATIONS_DIR;
 20
 21actions!(
 22    assistant,
 23    [
 24        NewConversation,
 25        Assist,
 26        Split,
 27        CycleMessageRole,
 28        QuoteSelection,
 29        ToggleFocus,
 30        ResetKey,
 31        InlineAssist,
 32        ToggleIncludeConversation,
 33        ToggleRetrieveContext,
 34    ]
 35);
 36
 37#[derive(
 38    Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize,
 39)]
 40struct MessageId(usize);
 41
 42#[derive(Clone, Debug, Serialize, Deserialize)]
 43struct MessageMetadata {
 44    role: Role,
 45    sent_at: DateTime<Local>,
 46    status: MessageStatus,
 47}
 48
 49#[derive(Clone, Debug, Serialize, Deserialize)]
 50enum MessageStatus {
 51    Pending,
 52    Done,
 53    Error(SharedString),
 54}
 55
 56#[derive(Serialize, Deserialize)]
 57struct SavedMessage {
 58    id: MessageId,
 59    start: usize,
 60}
 61
 62#[derive(Serialize, Deserialize)]
 63struct SavedConversation {
 64    id: Option<String>,
 65    zed: String,
 66    version: String,
 67    text: String,
 68    messages: Vec<SavedMessage>,
 69    message_metadata: HashMap<MessageId, MessageMetadata>,
 70    summary: String,
 71    api_url: Option<String>,
 72    model: OpenAiModel,
 73}
 74
 75impl SavedConversation {
 76    const VERSION: &'static str = "0.1.0";
 77}
 78
 79struct SavedConversationMetadata {
 80    title: String,
 81    path: PathBuf,
 82    mtime: chrono::DateTime<chrono::Local>,
 83}
 84
 85impl SavedConversationMetadata {
 86    pub async fn list(fs: Arc<dyn Fs>) -> Result<Vec<Self>> {
 87        fs.create_dir(&CONVERSATIONS_DIR).await?;
 88
 89        let mut paths = fs.read_dir(&CONVERSATIONS_DIR).await?;
 90        let mut conversations = Vec::<SavedConversationMetadata>::new();
 91        while let Some(path) = paths.next().await {
 92            let path = path?;
 93            if path.extension() != Some(OsStr::new("json")) {
 94                continue;
 95            }
 96
 97            let pattern = r" - \d+.zed.json$";
 98            let re = Regex::new(pattern).unwrap();
 99
100            let metadata = fs.metadata(&path).await?;
101            if let Some((file_name, metadata)) = path
102                .file_name()
103                .and_then(|name| name.to_str())
104                .zip(metadata)
105            {
106                let title = re.replace(file_name, "");
107                conversations.push(Self {
108                    title: title.into_owned(),
109                    path,
110                    mtime: metadata.mtime.into(),
111                });
112            }
113        }
114        conversations.sort_unstable_by_key(|conversation| Reverse(conversation.mtime));
115
116        Ok(conversations)
117    }
118}
119
120pub fn init(cx: &mut AppContext) {
121    assistant_panel::init(cx);
122}
123
124#[cfg(test)]
125#[ctor::ctor]
126fn init_logger() {
127    if std::env::var("RUST_LOG").is_ok() {
128        env_logger::init();
129    }
130}