1use crate::{
2 error::{PromptError, Result},
3 BuildChatPrompt,
4};
5use endpoints::chat::{
6 ChatCompletionAssistantMessage, ChatCompletionRequestMessage, ChatCompletionSystemMessage,
7 ChatCompletionToolMessage, ChatCompletionUserMessage, ChatCompletionUserMessageContent,
8 ContentPart, Tool,
9};
10
11#[derive(Debug, Default, Clone)]
13pub struct NemotronChatPrompt;
14impl NemotronChatPrompt {
15 fn create_system_prompt(&self, message: &ChatCompletionSystemMessage) -> String {
17 let content = message.content();
18 match content.is_empty() {
19 true => String::from("<extra_id_0>System\nYou are a helpful, respectful and honest assistant. Always answer as short as possible, while being safe."),
20 false =>format!(
21 "<extra_id_0>System\n{content}"
22 )
23 }
24 }
25
26 fn append_user_message(
28 &self,
29 chat_history: impl AsRef<str>,
30 system_prompt: impl AsRef<str>,
31 message: &ChatCompletionUserMessage,
32 ) -> String {
33 let content = match message.content() {
34 ChatCompletionUserMessageContent::Text(text) => text.to_string(),
35 ChatCompletionUserMessageContent::Parts(parts) => {
36 let mut content = String::new();
37 for part in parts {
38 if let ContentPart::Text(text_content) = part {
39 content.push_str(text_content.text());
40 content.push('\n');
41 }
42 }
43 content
44 }
45 };
46
47 match chat_history.as_ref().is_empty() {
48 true => format!(
49 "{system_prompt}\n<extra_id_1>User\n{user_message}",
50 system_prompt = system_prompt.as_ref().trim(),
51 user_message = content.trim(),
52 ),
53 false => format!(
54 "{chat_history}\n<extra_id_1>User\n{user_message}",
55 chat_history = chat_history.as_ref().trim(),
56 user_message = content.trim(),
57 ),
58 }
59 }
60
61 fn append_assistant_message(
63 &self,
64 chat_history: impl AsRef<str>,
65 message: &ChatCompletionAssistantMessage,
66 ) -> Result<String> {
67 let content = match message.content() {
68 Some(content) => content.to_string(),
69 None => match message.tool_calls().is_some() {
71 true => String::new(),
72 false => return Err(PromptError::NoAssistantMessage),
73 },
74 };
75
76 Ok(format!(
77 "{chat_history}<extra_id_1>Assistant\n{assistant_message}",
78 chat_history = chat_history.as_ref().trim(),
79 assistant_message = content.trim(),
80 ))
81 }
82}
83impl BuildChatPrompt for NemotronChatPrompt {
84 fn build(&self, messages: &mut Vec<ChatCompletionRequestMessage>) -> Result<String> {
85 if messages.is_empty() {
86 return Err(crate::error::PromptError::NoMessages);
87 }
88
89 let system_prompt = match messages[0] {
91 ChatCompletionRequestMessage::System(ref message) => {
92 self.create_system_prompt(message)
93 }
94 _ => String::from("<extra_id_0>System\nYou are a helpful, respectful and honest assistant. Always answer as short as possible, while being safe."),
95 };
96
97 let mut prompt = String::new();
99 for message in messages {
100 match message {
101 ChatCompletionRequestMessage::User(message) => {
102 prompt = self.append_user_message(&prompt, &system_prompt, message);
103 }
104 ChatCompletionRequestMessage::Assistant(message) => {
105 prompt = self.append_assistant_message(&prompt, message)?;
106 }
107 _ => continue,
108 }
109 }
110
111 prompt.push_str("\n<extra_id_1>Assistant\n");
112
113 Ok(prompt)
114 }
115}
116
117#[derive(Debug, Default, Clone)]
119pub struct NemotronToolPrompt;
120impl NemotronToolPrompt {
121 fn create_system_prompt(&self, message: &ChatCompletionSystemMessage) -> String {
123 let content = message.content();
124 match content.is_empty() {
125 true => String::from("<|im_start|>system\nAnswer as concisely as possible.<|im_end|>"),
126 false => format!("<|im_start|>system\n{content}<|im_end|>"),
127 }
128 }
129
130 fn create_system_prompt_tool(
131 &self,
132 message: &ChatCompletionSystemMessage,
133 tools: Option<&[Tool]>,
134 ) -> String {
135 let content = message.content();
136 match content.is_empty() {
137 true => match tools {
138 Some(tools) => {
139 let available_tools = serde_json::to_string(tools).unwrap();
140 let tools = format!("<tool> {available_tools} </tool>");
141
142 let begin = r#"<extra_id_0>System\nYou are a helpful, respectful and honest assistant. Always answer as short as possible, while being safe."#;
143
144 format!("{begin}\n\n{tools}")
145 }
146 None => {
147 String::from("<extra_id_0>System\nYou are a helpful, respectful and honest assistant. Always answer as short as possible, while being safe.")
148 }
149 },
150 false => match tools {
151 Some(tools) => {
152 let available_tools = serde_json::to_string(tools).unwrap();
153 let tools = format!("<tool> {available_tools} </tool>");
154
155 let begin = format!(
156 "<extra_id_0>System\n{content}"
157 );
158
159 format!("{begin}\n\n{tools}")
160 }
161 None => {
162 format!(
163 "<extra_id_0>System\n{content}"
164 )
165 }
166 },
167 }
168 }
169
170 fn append_user_message(
172 &self,
173 chat_history: impl AsRef<str>,
174 system_prompt: impl AsRef<str>,
175 message: &ChatCompletionUserMessage,
176 ) -> String {
177 let content = match message.content() {
178 ChatCompletionUserMessageContent::Text(text) => text.to_string(),
179 ChatCompletionUserMessageContent::Parts(parts) => {
180 let mut content = String::new();
181 for part in parts {
182 if let ContentPart::Text(text_content) = part {
183 content.push_str(text_content.text());
184 content.push('\n');
185 }
186 }
187 content
188 }
189 };
190
191 match chat_history.as_ref().is_empty() {
192 true => format!(
193 "{system_prompt}\n\n<extra_id_1>User\n{user_message}",
194 system_prompt = system_prompt.as_ref().trim(),
195 user_message = content.trim(),
196 ),
197 false => format!(
198 "{chat_history}\n<extra_id_1>User\n{user_message}",
199 chat_history = chat_history.as_ref().trim(),
200 user_message = content.trim(),
201 ),
202 }
203 }
204
205 fn append_assistant_message(
207 &self,
208 chat_history: impl AsRef<str>,
209 message: &ChatCompletionAssistantMessage,
210 ) -> Result<String> {
211 let content = match message.content() {
212 Some(content) => content.to_string(),
213 None => match message.tool_calls().is_some() {
215 true => String::new(),
216 false => return Err(PromptError::NoAssistantMessage),
217 },
218 };
219
220 Ok(format!(
221 "{chat_history}<extra_id_1>Assistant\n{assistant_message}",
222 chat_history = chat_history.as_ref().trim(),
223 assistant_message = content.trim(),
224 ))
225 }
226
227 fn append_tool_message(
229 &self,
230 chat_history: impl AsRef<str>,
231 message: &ChatCompletionToolMessage,
232 ) -> String {
233 format!(
234 "{chat_history}\n<extra_id_1>Tool\n{tool_message}",
235 chat_history = chat_history.as_ref().trim(),
236 tool_message = message.content().trim(),
237 )
238 }
239}
240impl BuildChatPrompt for NemotronToolPrompt {
241 fn build(&self, messages: &mut Vec<ChatCompletionRequestMessage>) -> Result<String> {
242 if messages.is_empty() {
243 return Err(crate::error::PromptError::NoMessages);
244 }
245
246 let system_prompt = match messages[0] {
248 ChatCompletionRequestMessage::System(ref message) => self.create_system_prompt(message),
249 _ => String::from("<|im_start|>system\nAnswer as concisely as possible.<|im_end|>"),
250 };
251
252 let mut prompt = String::new();
254 for message in messages {
255 match message {
256 ChatCompletionRequestMessage::User(message) => {
257 prompt = self.append_user_message(&prompt, &system_prompt, message);
258 }
259 ChatCompletionRequestMessage::Assistant(message) => {
260 prompt = self.append_assistant_message(&prompt, message)?;
261 }
262 ChatCompletionRequestMessage::Tool(message) => {
263 prompt = self.append_tool_message(&prompt, message);
264 }
265 _ => continue,
266 }
267 }
268
269 prompt.push_str("\n<|im_start|>assistant");
270
271 Ok(prompt)
272 }
273
274 fn build_with_tools(
275 &self,
276 messages: &mut Vec<ChatCompletionRequestMessage>,
277 tools: Option<&[Tool]>,
278 ) -> Result<String> {
279 if messages.is_empty() {
280 return Err(crate::error::PromptError::NoMessages);
281 }
282
283 let system_prompt = match messages[0] {
285 ChatCompletionRequestMessage::System(ref message) => {
286 self.create_system_prompt_tool(message, tools)
287 }
288 _ => match tools {
289 Some(tools) => {
290 let mut tools_s = String::new();
291 for tool in tools {
292 let available_tool = serde_json::to_string(&tool.function).unwrap();
293
294 let tool = format!("<tool> {available_tool} </tool>\n");
295
296 tools_s.push_str(&tool);
297 }
298
299 let begin = r#"<extra_id_0>System\nYou are a helpful, respectful and honest assistant. Always answer as short as possible, while being safe."#;
300
301 format!("{}\n{}", begin, tools_s.trim())
302 }
303 None => {
304 String::from("<|im_start|>system\nAnswer as concisely as possible.<|im_end|>")
305 }
306 },
307 };
308
309 let mut prompt = String::new();
311 for message in messages {
312 match message {
313 ChatCompletionRequestMessage::User(message) => {
314 prompt = self.append_user_message(&prompt, &system_prompt, message);
315 }
316 ChatCompletionRequestMessage::Assistant(message) => {
317 prompt = self.append_assistant_message(&prompt, message)?;
318 }
319 ChatCompletionRequestMessage::Tool(message) => {
320 prompt = self.append_tool_message(&prompt, message);
321 }
322 _ => continue,
323 }
324 }
325
326 prompt.push_str("\n<extra_id_1>Assistant\n");
327
328 Ok(prompt)
329 }
330}