context.rs

  1use gpui::SharedString;
  2use language_model::{LanguageModelRequestMessage, MessageContent};
  3use serde::{Deserialize, Serialize};
  4use ui::prelude::*;
  5use util::post_inc;
  6
  7#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Serialize, Deserialize)]
  8pub struct ContextId(pub(crate) usize);
  9
 10impl ContextId {
 11    pub fn post_inc(&mut self) -> Self {
 12        Self(post_inc(&mut self.0))
 13    }
 14}
 15
 16/// Some context attached to a message in a thread.
 17#[derive(Debug, Clone)]
 18pub struct Context {
 19    pub id: ContextId,
 20    pub name: SharedString,
 21    pub kind: ContextKind,
 22    pub text: SharedString,
 23    pub icon: IconName,
 24}
 25
 26#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 27pub enum ContextKind {
 28    File,
 29    Directory,
 30    FetchedUrl,
 31    Thread,
 32}
 33
 34impl ContextKind {
 35    pub fn icon(&self) -> IconName {
 36        match self {
 37            ContextKind::File => IconName::File,
 38            ContextKind::Directory => IconName::Folder,
 39            ContextKind::FetchedUrl => IconName::Globe,
 40            ContextKind::Thread => IconName::MessageCircle,
 41        }
 42    }
 43}
 44
 45pub fn attach_context_to_message(
 46    message: &mut LanguageModelRequestMessage,
 47    context: impl IntoIterator<Item = Context>,
 48) {
 49    let mut file_context = String::new();
 50    let mut directory_context = String::new();
 51    let mut fetch_context = String::new();
 52    let mut thread_context = String::new();
 53
 54    for context in context.into_iter() {
 55        match context.kind {
 56            ContextKind::File => {
 57                file_context.push_str(&context.text);
 58                file_context.push('\n');
 59            }
 60            ContextKind::Directory => {
 61                directory_context.push_str(&context.text);
 62                directory_context.push('\n');
 63            }
 64            ContextKind::FetchedUrl => {
 65                fetch_context.push_str(&context.name);
 66                fetch_context.push('\n');
 67                fetch_context.push_str(&context.text);
 68                fetch_context.push('\n');
 69            }
 70            ContextKind::Thread => {
 71                thread_context.push_str(&context.name);
 72                thread_context.push('\n');
 73                thread_context.push_str(&context.text);
 74                thread_context.push('\n');
 75            }
 76        }
 77    }
 78
 79    let mut context_text = String::new();
 80    if !file_context.is_empty() {
 81        context_text.push_str("The following files are available:\n");
 82        context_text.push_str(&file_context);
 83    }
 84
 85    if !directory_context.is_empty() {
 86        context_text.push_str("The following directories are available:\n");
 87        context_text.push_str(&directory_context);
 88    }
 89
 90    if !fetch_context.is_empty() {
 91        context_text.push_str("The following fetched results are available\n");
 92        context_text.push_str(&fetch_context);
 93    }
 94
 95    if !thread_context.is_empty() {
 96        context_text.push_str("The following previous conversation threads are available\n");
 97        context_text.push_str(&thread_context);
 98    }
 99
100    if !context_text.is_empty() {
101        message.content.push(MessageContent::Text(context_text));
102    }
103}