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}