context.rs

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