alith_client/workflows/reason/
one_round.rs1use super::{
2 PrimitiveTrait, ReasonResult, ReasonTrait, SentencesPrimitive, decision::DecisionTrait,
3};
4use crate::components::{
5 InstructPromptTrait,
6 cascade::{CascadeFlow, step::StepConfig},
7 instruct_prompt::InstructPrompt,
8};
9use alith_interface::requests::{
10 completion::CompletionRequest,
11 req_components::{RequestConfig, RequestConfigTrait},
12};
13
14pub struct ReasonOneRound<P> {
15 pub reasoning_sentences: u8,
16 pub conclusion_sentences: u8,
17 pub result_can_be_none: bool,
18 pub primitive: P,
19 pub base_req: CompletionRequest,
20 pub instruct_prompt: InstructPrompt,
21}
22
23impl<P: PrimitiveTrait + ReasonTrait> ReasonOneRound<P> {
24 pub async fn return_primitive(&mut self) -> crate::Result<P::PrimitiveResult> {
25 let res = self.return_result().await?;
26 if let Some(primitive_result) =
27 self.primitive.result_index_to_primitive(res.result_index)?
28 {
29 Ok(primitive_result)
30 } else {
31 Err(anyhow::format_err!("No result returned."))
32 }
33 }
34
35 pub async fn return_optional_primitive(&mut self) -> crate::Result<Option<P::PrimitiveResult>> {
36 let res = self.return_optional_result().await?;
37 self.primitive.result_index_to_primitive(res.result_index)
38 }
39
40 pub async fn return_result(&mut self) -> crate::Result<ReasonResult> {
41 self.result_can_be_none = false;
42
43 let mut flow = match self.reason_one_round() {
44 Ok(flow) => flow,
45 Err(e) => {
46 crate::error!("Error creating reason one round flow: {}", e);
47 return Err(e);
48 }
49 };
50 flow.run_all_rounds(&mut self.base_req).await?;
51
52 ReasonResult::new(flow, &self.primitive, &self.base_req)
53 }
54
55 pub async fn return_optional_result(&mut self) -> crate::Result<ReasonResult> {
56 self.result_can_be_none = true;
57 let mut flow = match self.reason_one_round() {
58 Ok(flow) => flow,
59 Err(e) => {
60 crate::error!("Error creating reason one round flow: {}", e);
61 return Err(e);
62 }
63 };
64 flow.run_all_rounds(&mut self.base_req).await?;
65 ReasonResult::new(flow, &self.primitive, &self.base_req)
66 }
67
68 pub fn reasoning_sentences(&mut self, reasoning_sentences: u8) -> &mut Self {
69 self.reasoning_sentences = reasoning_sentences;
70 self
71 }
72
73 pub fn conclusion_sentences(&mut self, conclusion_sentences: u8) -> &mut Self {
74 self.conclusion_sentences = conclusion_sentences;
75 self
76 }
77
78 fn reason_one_round(&mut self) -> crate::Result<CascadeFlow> {
79 let mut flow = CascadeFlow::new("Reason One Round");
80
81 flow.new_round(
82 "A request will be provided. Think out loud about the request. State the arguments before arriving at a conclusion with, 'Therefore, we can conclude:...', and finish with a solution by saying, 'Thus, the solution...'. With no yapping.").add_guidance_step(
83 &StepConfig {
84 ..StepConfig::default()
85 },
86 "'no yapping' refers to a design principle or behavior where the AI model provides direct, concise responses without unnecessary verbosity or filler content. Therefore, we can conclude: The user would like to get straight to the point. Thus, the solution is to to resolve the request as efficiently as possible.",
87 );
88
89 let task = self.build_task()?;
90
91 let step_config = StepConfig {
93 step_prefix: Some("Thinking out loud about the users request...".to_string()),
94 stop_word_done: "Therefore, we can conclude".to_string(),
95 cache_prompt: false, grammar: SentencesPrimitive::default()
97 .min_count(1)
98 .max_count(self.reasoning_sentences)
99 .grammar(),
100 ..StepConfig::default()
101 };
102
103 flow.new_round(task).add_inference_step(&step_config);
104
105 let step_config = StepConfig {
107 step_prefix: Some(format!(
108 "The user requested a conclusion of {}. Therefore, we can conclude:",
109 self.primitive.solution_description(self.result_can_be_none),
110 )),
111 stop_word_done: "Thus, the solution".to_string(),
112 grammar: SentencesPrimitive::default()
113 .min_count(1)
114 .max_count(self.conclusion_sentences)
115 .grammar(),
116
117 ..StepConfig::default()
118 };
119 flow.last_round()?.add_inference_step(&step_config);
120
121 if let Some(instructions) = self.instruct_prompt.build_instructions() {
123 let instructions_restatement =
124 format!("The user's original request was '{}'.", &instructions,);
125 let step_config = StepConfig {
126 step_prefix: None,
127 grammar: SentencesPrimitive::default().grammar(),
128 ..StepConfig::default()
129 };
130 flow.last_round()?
131 .add_guidance_step(&step_config, instructions_restatement);
132 };
133
134 let solution = format!(
136 "Thus, the {} solution to the user's request is:",
137 self.primitive.type_description(self.result_can_be_none),
138 );
139 let step_config = StepConfig {
140 step_prefix: Some(solution),
141 stop_word_no_result: self
142 .primitive
143 .stop_word_result_is_none(self.result_can_be_none),
144 grammar: self.primitive.grammar(),
145 ..StepConfig::default()
146 };
147 flow.last_round()?.add_inference_step(&step_config);
148
149 Ok(flow)
150 }
151
152 fn build_task(&mut self) -> crate::Result<String> {
153 let instructions = self.instruct_prompt.build_instructions();
154 let supporting_material = self.instruct_prompt.build_supporting_material();
155
156 Ok(match (instructions, supporting_material) {
157 (Some(instructions), Some(supporting_material)) => {
158 format!(
159 "The user provided some supporting material: {supporting_material}\n The user's request is: {instructions}",
160 )
161 }
162 (Some(instructions), None) => {
163 format!("The user's request is: {instructions}",)
164 }
165 (None, Some(supporting_material)) => {
166 format!("The user's request is: {supporting_material}",)
167 }
168 (None, None) => {
169 return Err(anyhow::format_err!(
170 "No instructions or supporting material provided."
171 ));
172 }
173 })
174 }
175}
176
177impl<P: PrimitiveTrait> RequestConfigTrait for ReasonOneRound<P> {
178 fn config(&mut self) -> &mut RequestConfig {
179 &mut self.base_req.config
180 }
181
182 fn reset_request(&mut self) {
183 self.instruct_prompt.reset_instruct_prompt();
184 self.base_req.reset_completion_request();
185 }
186}
187
188impl<P: PrimitiveTrait + ReasonTrait> InstructPromptTrait for ReasonOneRound<P> {
189 fn instruct_prompt_mut(&mut self) -> &mut InstructPrompt {
190 &mut self.instruct_prompt
191 }
192}
193
194impl<P: PrimitiveTrait + ReasonTrait> DecisionTrait for ReasonOneRound<P> {
195 type ReasonPrimitive = P;
196 fn base_req(&self) -> &CompletionRequest {
197 &self.base_req
198 }
199
200 fn base_req_mut(&mut self) -> &mut CompletionRequest {
201 &mut self.base_req
202 }
203
204 fn primitive(&self) -> &Self::ReasonPrimitive {
205 &self.primitive
206 }
207
208 async fn return_reason_result(
209 &mut self,
210 result_can_be_none: bool,
211 ) -> crate::Result<ReasonResult> {
212 if result_can_be_none {
213 self.return_optional_result().await
214 } else {
215 self.return_result().await
216 }
217 }
218}