ferrin_core/generate_text/
prepare_step.rs1use ferrin_message::Message;
4use ferrin_spec::BoxFuture;
5use ferrin_spec::JsonValue;
6use ferrin_spec::LanguageModelRef;
7use ferrin_spec::ToolChoice;
8use ferrin_spec::ToolName;
9
10use super::StepResult;
11use crate::error::Error;
12use crate::prompt::CallSettings;
13use crate::prompt::Instructions;
14use crate::telemetry::ModelIdentity;
15
16#[derive(Debug)]
18pub struct PrepareStepContext<'a> {
19 pub steps: &'a [StepResult],
21 pub step_number: u32,
23 pub model: &'a ModelIdentity,
25 pub instructions: Option<&'a Instructions>,
27 pub messages: &'a [Message],
29 pub initial_messages: &'a [Message],
31 pub response_messages: &'a [Message],
33 pub tools_context: Option<&'a JsonValue>,
35}
36
37#[derive(Debug, Default)]
40pub struct StepOverrides {
41 pub model: Option<LanguageModelRef>,
43 pub tool_choice: Option<ToolChoice>,
45 pub active_tools: Option<Vec<ToolName>>,
47 pub tool_order: Option<Vec<ToolName>>,
49 pub instructions: Option<Instructions>,
51 pub messages: Option<Vec<Message>>,
53 pub tools_context: Option<JsonValue>,
55 pub settings: Option<CallSettings>,
57}
58
59impl StepOverrides {
60 #[must_use]
62 pub fn none() -> Self {
63 Self::default()
64 }
65
66 #[must_use]
68 pub fn with_model(mut self, model: impl Into<LanguageModelRef>) -> Self {
69 self.model = Some(model.into());
70 self
71 }
72
73 #[must_use]
75 pub fn with_tool_choice(mut self, tool_choice: ToolChoice) -> Self {
76 self.tool_choice = Some(tool_choice);
77 self
78 }
79
80 #[must_use]
82 pub fn with_active_tools(
83 mut self,
84 names: impl IntoIterator<Item = impl Into<ToolName>>,
85 ) -> Self {
86 self.active_tools = Some(names.into_iter().map(Into::into).collect());
87 self
88 }
89
90 #[must_use]
92 pub fn with_tool_order(mut self, names: impl IntoIterator<Item = impl Into<ToolName>>) -> Self {
93 self.tool_order = Some(names.into_iter().map(Into::into).collect());
94 self
95 }
96
97 #[must_use]
99 pub fn with_instructions(mut self, instructions: impl Into<Instructions>) -> Self {
100 self.instructions = Some(instructions.into());
101 self
102 }
103
104 #[must_use]
106 pub fn with_messages(mut self, messages: impl IntoIterator<Item = Message>) -> Self {
107 self.messages = Some(messages.into_iter().collect());
108 self
109 }
110
111 #[must_use]
113 pub fn with_tools_context(mut self, context: JsonValue) -> Self {
114 self.tools_context = Some(context);
115 self
116 }
117
118 #[must_use]
120 pub fn with_settings(mut self, settings: CallSettings) -> Self {
121 self.settings = Some(settings);
122 self
123 }
124}
125
126pub trait PrepareStep: Send + Sync {
131 fn prepare_step<'a>(
133 &'a self,
134 ctx: PrepareStepContext<'a>,
135 ) -> BoxFuture<'a, Result<StepOverrides, Error>>;
136}
137
138impl<F> PrepareStep for F
139where
140 F: Fn(&PrepareStepContext<'_>) -> StepOverrides + Send + Sync,
141{
142 fn prepare_step<'a>(
143 &'a self,
144 ctx: PrepareStepContext<'a>,
145 ) -> BoxFuture<'a, Result<StepOverrides, Error>> {
146 let overrides = self(&ctx);
147 Box::pin(async move { Ok(overrides) })
148 }
149}