synaptic_parsers/
numbered_list_parser.rs1use async_trait::async_trait;
2use synaptic_core::{RunnableConfig, SynapticError};
3use synaptic_runnables::Runnable;
4
5use crate::FormatInstructions;
6
7pub struct NumberedListOutputParser;
9
10impl FormatInstructions for NumberedListOutputParser {
11 fn get_format_instructions(&self) -> String {
12 "Your response should be a numbered list (e.g., `1. item`, `2. item`).".to_string()
13 }
14}
15
16#[async_trait]
17impl Runnable<String, Vec<String>> for NumberedListOutputParser {
18 async fn invoke(
19 &self,
20 input: String,
21 _config: &RunnableConfig,
22 ) -> Result<Vec<String>, SynapticError> {
23 let items: Vec<String> = input
24 .lines()
25 .filter_map(|line| {
26 let trimmed = line.trim();
27 if trimmed.is_empty() {
28 return None;
29 }
30 let dot_pos = trimmed.find('.')?;
32 let prefix = &trimmed[..dot_pos];
33 if prefix.is_empty() || !prefix.chars().all(|c| c.is_ascii_digit()) {
34 return None;
35 }
36 let after_dot = &trimmed[dot_pos + 1..];
38 let rest = after_dot
39 .strip_prefix(' ')
40 .or_else(|| after_dot.strip_prefix('\t'))?;
41 let item = rest.trim().to_string();
42 if item.is_empty() {
43 None
44 } else {
45 Some(item)
46 }
47 })
48 .collect();
49
50 Ok(items)
51 }
52}