#[ allow( clippy::missing_inline_in_public_items ) ]
mod private
{
use serde::{ Serialize, Deserialize };
#[ derive( Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub struct CacheControl
{
#[ serde( rename = "type" ) ]
pub cache_type : String,
}
impl CacheControl
{
pub fn ephemeral() -> Self
{
Self { cache_type : "ephemeral".to_string() }
}
}
impl From< String > for SystemPrompt
{
fn from( text : String ) -> Self
{
Self { text, cache_control : None }
}
}
impl From< &str > for SystemPrompt
{
fn from( text : &str ) -> Self
{
Self { text : text.to_string(), cache_control : None }
}
}
#[ derive( Debug, Clone, PartialEq, Serialize, Deserialize ) ]
pub struct SystemPrompt
{
pub text : String,
#[ serde( skip_serializing_if = "Option::is_none" ) ]
pub cache_control : Option< CacheControl >,
}
#[ derive( Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub struct SystemContent
{
#[ serde( rename = "type" ) ]
pub r#type : String,
pub text : String,
#[ serde( skip_serializing_if = "Option::is_none" ) ]
pub cache_control : Option< CacheControl >,
}
impl SystemContent
{
pub fn text< S : Into< String > >( text : S ) -> Self
{
Self
{
r#type : "text".to_string(),
text : text.into(),
cache_control : None,
}
}
#[ must_use ]
pub fn with_cache_control( mut self, cache_control : CacheControl ) -> Self
{
self.cache_control = Some( cache_control );
self
}
pub fn validate( &self ) -> Result< (), String >
{
if self.text.is_empty()
{
return Err( "System content text cannot be empty".to_string() );
}
if self.r#type != "text"
{
return Err( format!( "Invalid system content type : {}", self.r#type ) );
}
Ok( () )
}
pub fn has_cache_control( &self ) -> bool
{
self.cache_control.is_some()
}
}
impl From< &str > for SystemContent
{
fn from( text : &str ) -> Self
{
Self::text( text )
}
}
impl From< String > for SystemContent
{
fn from( text : String ) -> Self
{
Self::text( text )
}
}
#[ derive( Debug, Clone, Default ) ]
pub struct SystemInstructions
{
parts : Vec< SystemContent >,
}
impl SystemInstructions
{
pub fn new() -> Self
{
Self
{
parts : Vec::new(),
}
}
#[ must_use ]
pub fn add_text< S : Into< String > >( mut self, text : S ) -> Self
{
self.parts.push( SystemContent::text( text ) );
self
}
#[ must_use ]
pub fn add_cached_text< S : Into< String > >( mut self, text : S ) -> Self
{
let content = SystemContent::text( text )
.with_cache_control( CacheControl::ephemeral() );
self.parts.push( content );
self
}
#[ must_use ]
#[ allow( clippy::should_implement_trait ) ]
pub fn add( mut self, content : SystemContent ) -> Self
{
self.parts.push( content );
self
}
#[ must_use ]
pub fn build( self ) -> Vec< SystemContent >
{
self.parts
}
pub fn validate( &self ) -> Result< (), String >
{
if self.parts.is_empty()
{
return Err( "System instructions cannot be empty".to_string() );
}
for ( idx, content ) in self.parts.iter().enumerate()
{
content.validate()
.map_err( |e| format!( "Invalid content at index {idx}: {e}" ) )?;
}
Ok( () )
}
pub fn len( &self ) -> usize
{
self.parts.len()
}
pub fn is_empty( &self ) -> bool
{
self.parts.is_empty()
}
}
}
crate::mod_interface!
{
exposed use CacheControl;
exposed use SystemPrompt;
exposed use SystemContent;
exposed use SystemInstructions;
}