synaptic_parsers/
list_parser.rs1use async_trait::async_trait;
2use synaptic_core::{RunnableConfig, SynapticError};
3use synaptic_runnables::Runnable;
4
5use crate::FormatInstructions;
6
7#[derive(Debug, Clone)]
9pub enum ListSeparator {
10 Newline,
11 Comma,
12 Custom(String),
13}
14
15pub struct ListOutputParser {
17 separator: ListSeparator,
18}
19
20impl ListOutputParser {
21 pub fn new(separator: ListSeparator) -> Self {
22 Self { separator }
23 }
24
25 pub fn newline() -> Self {
27 Self::new(ListSeparator::Newline)
28 }
29
30 pub fn comma() -> Self {
32 Self::new(ListSeparator::Comma)
33 }
34}
35
36impl Default for ListOutputParser {
37 fn default() -> Self {
38 Self::newline()
39 }
40}
41
42impl FormatInstructions for ListOutputParser {
43 fn get_format_instructions(&self) -> String {
44 let sep_desc = match &self.separator {
45 ListSeparator::Newline => "newlines",
46 ListSeparator::Comma => "commas",
47 ListSeparator::Custom(s) => s.as_str(),
48 };
49 format!("Your response should be a list of items separated by {sep_desc}.")
50 }
51}
52
53#[async_trait]
54impl Runnable<String, Vec<String>> for ListOutputParser {
55 async fn invoke(
56 &self,
57 input: String,
58 _config: &RunnableConfig,
59 ) -> Result<Vec<String>, SynapticError> {
60 let sep = match &self.separator {
61 ListSeparator::Newline => "\n",
62 ListSeparator::Comma => ",",
63 ListSeparator::Custom(s) => s.as_str(),
64 };
65
66 let items: Vec<String> = input
67 .split(sep)
68 .map(|s| s.trim().to_string())
69 .filter(|s| !s.is_empty())
70 .collect();
71
72 Ok(items)
73 }
74}