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