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    model: OpenAiModel,
 72}
 73
 74impl SavedConversation {
 75    const VERSION: &'static str = "0.1.0";
 76}
 77
 78struct SavedConversationMetadata {
 79    title: String,
 80    path: PathBuf,
 81    mtime: chrono::DateTime<chrono::Local>,
 82}
 83
 84impl SavedConversationMetadata {
 85    pub async fn list(fs: Arc<dyn Fs>) -> Result<Vec<Self>> {
 86        fs.create_dir(&CONVERSATIONS_DIR).await?;
 87
 88        let mut paths = fs.read_dir(&CONVERSATIONS_DIR).await?;
 89        let mut conversations = Vec::<SavedConversationMetadata>::new();
 90        while let Some(path) = paths.next().await {
 91            let path = path?;
 92            if path.extension() != Some(OsStr::new("json")) {
 93                continue;
 94            }
 95
 96            let pattern = r" - \d+.zed.json$";
 97            let re = Regex::new(pattern).unwrap();
 98
 99            let metadata = fs.metadata(&path).await?;
100            if let Some((file_name, metadata)) = path
101                .file_name()
102                .and_then(|name| name.to_str())
103                .zip(metadata)
104            {
105                let title = re.replace(file_name, "");
106                conversations.push(Self {
107                    title: title.into_owned(),
108                    path,
109                    mtime: metadata.mtime.into(),
110                });
111            }
112        }
113        conversations.sort_unstable_by_key(|conversation| Reverse(conversation.mtime));
114
115        Ok(conversations)
116    }
117}
118
119pub fn init(cx: &mut AppContext) {
120    assistant_panel::init(cx);
121}
122
123#[cfg(test)]
124#[ctor::ctor]
125fn init_logger() {
126    if std::env::var("RUST_LOG").is_ok() {
127        env_logger::init();
128    }
129}