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}