ferrin_core/middleware/builtin/
default_instructions.rs1use ferrin_spec::BoxFuture;
4use ferrin_spec::CallOptions;
5use ferrin_spec::error::ProviderError;
6use ferrin_spec::language_model::prompt::PromptMessage;
7
8use crate::middleware::LanguageModelMiddleware;
9use crate::middleware::MiddlewareContext;
10use crate::prompt::Instructions;
11
12#[derive(Debug, Clone)]
14pub struct DefaultInstructions {
15 instructions: Instructions,
16}
17
18#[must_use]
21pub fn default_instructions(instructions: impl Into<Instructions>) -> DefaultInstructions {
22 DefaultInstructions {
23 instructions: instructions.into(),
24 }
25}
26
27impl LanguageModelMiddleware for DefaultInstructions {
28 fn transform_params<'a>(
29 &'a self,
30 mut options: CallOptions,
31 _ctx: MiddlewareContext<'a>,
32 ) -> BoxFuture<'a, Result<CallOptions, ProviderError>> {
33 let has_system = options
34 .prompt
35 .iter()
36 .any(|message| matches!(message, PromptMessage::System { .. }));
37 if !has_system {
38 options.prompt.splice(
39 0..0,
40 self.instructions
41 .as_messages()
42 .iter()
43 .map(|message| PromptMessage::System {
44 content: message.content.clone(),
45 provider_options: message.provider_options.clone(),
46 }),
47 );
48 }
49 Box::pin(async move { Ok(options) })
50 }
51}