#[ allow( clippy::missing_inline_in_public_items ) ]
mod private
{
use crate::{
client::{ Client, ClientConfig },
CreateMessageRequest, CreateMessageResponse,
error::{ AnthropicError, AnthropicResult },
secret::Secret,
Message, messages::{ Content, Role },
};
#[ cfg( feature = "count-tokens" ) ]
use crate::{ CountMessageTokensRequest, CountMessageTokensResponse };
use std::{ sync::Arc, time::Duration };
use tokio::runtime::Runtime;
#[ derive( Debug, Clone ) ]
pub struct SyncClient
{
inner : Client,
runtime : SyncRuntime,
}
#[ derive( Debug ) ]
pub struct SyncRuntime
{
handle : Arc< Runtime >,
}
impl Clone for SyncRuntime
{
fn clone( &self ) -> Self
{
Self
{
handle : Arc::clone( &self.handle ),
}
}
}
#[ derive( Debug ) ]
pub struct SyncClientBuilder
{
timeout : Option< Duration >,
api_key : Option< String >,
base_url : Option< String >,
}
impl SyncRuntime
{
pub fn new() -> AnthropicResult< Self >
{
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.map_err( |e| AnthropicError::InvalidRequest( format!( "Failed to create runtime : {e}" ) ) )?;
Ok( Self
{
handle : Arc::new( rt ),
} )
}
pub fn block_on< F >( &self, future : F ) -> F::Output
where
F : core::future::Future,
{
self.handle.block_on( future )
}
pub fn handle( &self ) -> &Runtime
{
&self.handle
}
}
impl Default for SyncRuntime
{
fn default() -> Self
{
Self::new().expect( "Failed to create default runtime" )
}
}
impl SyncClient
{
pub fn new( api_key : &str ) -> AnthropicResult< Self >
{
let runtime = SyncRuntime::new()?;
let secret = Secret::new( api_key.to_string() )
.map_err( |e| AnthropicError::InvalidRequest( e.to_string() ) )?;
let inner = Client::new( secret );
Ok( Self
{
inner,
runtime,
} )
}
pub fn from_env() -> AnthropicResult< Self >
{
let runtime = SyncRuntime::new()?;
let inner = Client::from_env()?;
Ok( Self
{
inner,
runtime,
} )
}
pub fn from_workspace() -> AnthropicResult< Self >
{
let runtime = SyncRuntime::new()?;
let inner = Client::from_workspace()?;
Ok( Self
{
inner,
runtime,
} )
}
pub fn with_runtime( runtime : SyncRuntime, api_key : &str ) -> AnthropicResult< Self >
{
let secret = Secret::new( api_key.to_string() )
.map_err( |e| AnthropicError::InvalidRequest( e.to_string() ) )?;
let inner = Client::new( secret );
Ok( Self
{
inner,
runtime,
} )
}
pub fn has_api_key( &self ) -> bool
{
self.inner.api_key().is_some()
}
pub fn get_api_key( &self ) -> String
{
if self.has_api_key()
{
"sk-ant-*****".to_string()
}
else
{
"< NO_API_KEY >".to_string()
}
}
pub fn get_timeout( &self ) -> Duration
{
Duration::from_secs( 30 ) }
pub fn create_message( &self, request : &CreateMessageRequest ) -> AnthropicResult< CreateMessageResponse >
{
self.runtime.block_on( self.inner.create_message( request.clone() ) )
}
#[ cfg( feature = "streaming" ) ]
pub fn create_message_stream( &self, request : &CreateMessageRequest ) -> AnthropicResult< SyncStreamIterator >
{
let stream = self.runtime.block_on( self.inner.create_message_stream( request.clone() ) )?;
Ok( SyncStreamIterator
{
stream,
runtime : self.runtime.clone(),
} )
}
#[ cfg( feature = "count-tokens" ) ]
pub fn count_message_tokens( &self, request : &CountMessageTokensRequest ) -> AnthropicResult< CountMessageTokensResponse >
{
self.runtime.block_on( self.inner.count_message_tokens( request.clone() ) )
}
}
#[ cfg( feature = "streaming" ) ]
pub struct SyncStreamIterator
{
stream : crate::streaming::EventStream,
runtime : SyncRuntime,
}
#[ cfg( feature = "streaming" ) ]
impl core::fmt::Debug for SyncStreamIterator
{
fn fmt( &self, f : &mut core::fmt::Formatter< '_ > ) -> core::fmt::Result
{
f.debug_struct( "SyncStreamIterator" )
.field( "runtime", &self.runtime )
.finish_non_exhaustive()
}
}
#[ cfg( feature = "streaming" ) ]
impl Iterator for SyncStreamIterator
{
type Item = AnthropicResult< crate::streaming::StreamEvent >;
fn next( &mut self ) -> Option< Self::Item >
{
use futures::StreamExt;
self.runtime.block_on( self.stream.next() )
}
}
impl SyncClientBuilder
{
pub fn new() -> Self
{
Self
{
timeout : None,
api_key : None,
base_url : None,
}
}
#[ must_use ]
pub fn timeout( mut self, timeout : Duration ) -> Self
{
self.timeout = Some( timeout );
self
}
#[ must_use ]
pub fn api_key< S : Into< String > >( mut self, api_key : S ) -> Self
{
self.api_key = Some( api_key.into() );
self
}
#[ must_use ]
pub fn base_url< S : Into< String > >( mut self, base_url : S ) -> Self
{
self.base_url = Some( base_url.into() );
self
}
pub fn build_from_env( self ) -> AnthropicResult< SyncClient >
{
let runtime = SyncRuntime::new()?;
let mut config = ClientConfig::recommended();
if let Some( timeout ) = self.timeout
{
config.request_timeout = timeout;
}
if let Some( base_url ) = self.base_url
{
config.base_url = base_url;
}
let secret = Secret::load_from_env( "ANTHROPIC_API_KEY" )
.map_err( |e| AnthropicError::InvalidRequest( e.to_string() ) )?;
let inner = Client::with_config( secret, config );
Ok( SyncClient
{
inner,
runtime,
} )
}
pub fn build( self, api_key : &str ) -> AnthropicResult< SyncClient >
{
let runtime = SyncRuntime::new()?;
let mut config = ClientConfig::recommended();
if let Some( timeout ) = self.timeout
{
config.request_timeout = timeout;
}
if let Some( base_url ) = self.base_url
{
config.base_url = base_url;
}
let secret = Secret::new( api_key.to_string() )
.map_err( |e| AnthropicError::InvalidRequest( e.to_string() ) )?;
let inner = Client::with_config( secret, config );
Ok( SyncClient
{
inner,
runtime,
} )
}
}
impl Default for SyncClientBuilder
{
fn default() -> Self
{
Self::new()
}
}
impl CreateMessageRequest
{
pub fn new( model : &str ) -> Self
{
Self
{
model : model.to_string(),
max_tokens : 100, messages : vec![],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
}
}
pub fn add_user_message( &mut self, content : &str )
{
self.messages.push( Message::user( content ) );
}
pub fn add_message( &mut self, message : Message )
{
self.messages.push( message );
}
pub fn set_max_tokens( &mut self, max_tokens : u32 )
{
self.max_tokens = max_tokens;
}
pub fn set_system( &mut self, system : &str )
{
self.system = Some( vec![ crate::SystemContent::text( system ) ] );
}
pub fn set_temperature( &mut self, temperature : f32 )
{
self.temperature = Some( temperature );
}
}
impl Message
{
pub fn assistant_from_content( content : &[Content] ) -> Self
{
Self
{
role : Role::Assistant,
content : content.to_owned(),
cache_control : None,
}
}
}
impl SyncClient
{
pub fn from_async( client : Client ) -> AnthropicResult< Self >
{
let runtime = SyncRuntime::new()?;
Ok( Self
{
inner : client,
runtime,
} )
}
pub fn async_client( &self ) -> &Client
{
&self.inner
}
pub fn runtime( &self ) -> &SyncRuntime
{
&self.runtime
}
}
}
#[ cfg( all( feature = "sync-api", feature = "streaming" ) ) ]
crate::mod_interface!
{
exposed use
{
SyncClient,
SyncRuntime,
SyncClientBuilder,
SyncStreamIterator,
};
}
#[ cfg( all( feature = "sync-api", not( feature = "streaming" ) ) ) ]
crate::mod_interface!
{
exposed use
{
SyncClient,
SyncRuntime,
SyncClientBuilder,
};
}
#[ cfg( not( feature = "sync-api" ) ) ]
crate::mod_interface!
{
}