use ferrin_message::Message;
use ferrin_spec::BoxFuture;
use ferrin_spec::JsonValue;
use ferrin_spec::LanguageModelRef;
use ferrin_spec::ToolChoice;
use ferrin_spec::ToolName;
use super::StepResult;
use crate::error::Error;
use crate::prompt::CallSettings;
use crate::prompt::Instructions;
use crate::telemetry::ModelIdentity;
#[derive(Debug)]
pub struct PrepareStepContext<'a> {
pub steps: &'a [StepResult],
pub step_number: u32,
pub model: &'a ModelIdentity,
pub instructions: Option<&'a Instructions>,
pub messages: &'a [Message],
pub initial_messages: &'a [Message],
pub response_messages: &'a [Message],
pub tools_context: Option<&'a JsonValue>,
}
#[derive(Debug, Default)]
pub struct StepOverrides {
pub model: Option<LanguageModelRef>,
pub tool_choice: Option<ToolChoice>,
pub active_tools: Option<Vec<ToolName>>,
pub tool_order: Option<Vec<ToolName>>,
pub instructions: Option<Instructions>,
pub messages: Option<Vec<Message>>,
pub tools_context: Option<JsonValue>,
pub settings: Option<CallSettings>,
}
impl StepOverrides {
#[must_use]
pub fn none() -> Self {
Self::default()
}
#[must_use]
pub fn with_model(mut self, model: impl Into<LanguageModelRef>) -> Self {
self.model = Some(model.into());
self
}
#[must_use]
pub fn with_tool_choice(mut self, tool_choice: ToolChoice) -> Self {
self.tool_choice = Some(tool_choice);
self
}
#[must_use]
pub fn with_active_tools(
mut self,
names: impl IntoIterator<Item = impl Into<ToolName>>,
) -> Self {
self.active_tools = Some(names.into_iter().map(Into::into).collect());
self
}
#[must_use]
pub fn with_tool_order(mut self, names: impl IntoIterator<Item = impl Into<ToolName>>) -> Self {
self.tool_order = Some(names.into_iter().map(Into::into).collect());
self
}
#[must_use]
pub fn with_instructions(mut self, instructions: impl Into<Instructions>) -> Self {
self.instructions = Some(instructions.into());
self
}
#[must_use]
pub fn with_messages(mut self, messages: impl IntoIterator<Item = Message>) -> Self {
self.messages = Some(messages.into_iter().collect());
self
}
#[must_use]
pub fn with_tools_context(mut self, context: JsonValue) -> Self {
self.tools_context = Some(context);
self
}
#[must_use]
pub fn with_settings(mut self, settings: CallSettings) -> Self {
self.settings = Some(settings);
self
}
}
pub trait PrepareStep: Send + Sync {
fn prepare_step<'a>(
&'a self,
ctx: PrepareStepContext<'a>,
) -> BoxFuture<'a, Result<StepOverrides, Error>>;
}
impl<F> PrepareStep for F
where
F: Fn(&PrepareStepContext<'_>) -> StepOverrides + Send + Sync,
{
fn prepare_step<'a>(
&'a self,
ctx: PrepareStepContext<'a>,
) -> BoxFuture<'a, Result<StepOverrides, Error>> {
let overrides = self(&ctx);
Box::pin(async move { Ok(overrides) })
}
}