1use gpui::SharedString;
2use language_model::{LanguageModelRequestMessage, MessageContent};
3use project::ProjectEntryId;
4use serde::{Deserialize, Serialize};
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}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26pub enum ContextKind {
27 File(ProjectEntryId),
28 Directory,
29 FetchedUrl,
30 Thread,
31}
32
33pub fn attach_context_to_message(
34 message: &mut LanguageModelRequestMessage,
35 context: impl IntoIterator<Item = Context>,
36) {
37 let mut file_context = String::new();
38 let mut directory_context = String::new();
39 let mut fetch_context = String::new();
40 let mut thread_context = String::new();
41
42 for context in context.into_iter() {
43 match context.kind {
44 ContextKind::File(_) => {
45 file_context.push_str(&context.text);
46 file_context.push('\n');
47 }
48 ContextKind::Directory => {
49 directory_context.push_str(&context.text);
50 directory_context.push('\n');
51 }
52 ContextKind::FetchedUrl => {
53 fetch_context.push_str(&context.name);
54 fetch_context.push('\n');
55 fetch_context.push_str(&context.text);
56 fetch_context.push('\n');
57 }
58 ContextKind::Thread => {
59 thread_context.push_str(&context.name);
60 thread_context.push('\n');
61 thread_context.push_str(&context.text);
62 thread_context.push('\n');
63 }
64 }
65 }
66
67 let mut context_text = String::new();
68 if !file_context.is_empty() {
69 context_text.push_str("The following files are available:\n");
70 context_text.push_str(&file_context);
71 }
72
73 if !directory_context.is_empty() {
74 context_text.push_str("The following directories are available:\n");
75 context_text.push_str(&directory_context);
76 }
77
78 if !fetch_context.is_empty() {
79 context_text.push_str("The following fetched results are available\n");
80 context_text.push_str(&fetch_context);
81 }
82
83 if !thread_context.is_empty() {
84 context_text.push_str("The following previous conversation threads are available\n");
85 context_text.push_str(&thread_context);
86 }
87
88 if !context_text.is_empty() {
89 message.content.push(MessageContent::Text(context_text));
90 }
91}