use api_xai::{
Client, XaiEnvironmentImpl, Secret, ChatCompletionRequest,
Message, Tool, ToolResult,
execute_tool_calls_parallel, ClientApiAccessors
};
use serde_json::json;
#[ allow( clippy::too_many_lines ) ] #[ tokio::main ]
async fn main() -> Result< (), Box< dyn core::error::Error > >
{
println!( "đ ī¸ XAI Grok API - Enhanced Tools Demo\n" );
println!( "======================================\n" );
let secret = Secret::load_with_fallbacks( "XAI_API_KEY" )?;
let env = XaiEnvironmentImpl::new( secret )?;
let client = Client::build( env )?;
let weather_tool = Tool::function(
"get_weather",
"Get current weather for a location",
json!({
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name"
}
},
"required": ["location"]
})
);
let time_tool = Tool::function(
"get_time",
"Get current time for a timezone",
json!({
"type": "object",
"properties": {
"timezone": {
"type": "string",
"description": "Timezone (e.g., America/New_York)"
}
},
"required": ["timezone"]
})
);
let stock_tool = Tool::function(
"get_stock_price",
"Get stock price for a symbol",
json!({
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "Stock symbol (e.g., AAPL)"
}
},
"required": ["symbol"]
})
);
println!( "đ Available Tools:" );
println!( " 1. get_weather - Weather information" );
println!( " 2. get_time - Timezone information" );
println!( " 3. get_stock_price - Stock prices\n" );
let request = ChatCompletionRequest::former()
.model( "grok-2-1212".to_string() )
.messages( vec![
Message::user( "What's the weather in Tokyo, the current time in London, and Apple's stock price?" )
] )
.tools( vec![ weather_tool.clone(), time_tool.clone(), stock_tool.clone() ] )
.form();
println!( "đ¤ Sending request with multiple tools..." );
let response = client.chat().create( request ).await?;
if let Some( choice ) = response.choices.first()
{
if let Some( ref tool_calls ) = choice.message.tool_calls
{
println!( "â
Model requested {} tool call(s)\n", tool_calls.len() );
for ( i, call ) in tool_calls.iter().enumerate()
{
println!( " {}. {} ({})", i + 1, call.function.name, call.id );
println!( " Args : {}\n", call.function.arguments );
}
println!( "⥠Executing tool calls in parallel...\n" );
let start = std::time::Instant::now();
let results = execute_tool_calls_parallel(
tool_calls.clone(),
| call | async move {
tokio::time::sleep( core::time::Duration::from_millis( 500 ) ).await;
match call.function.name.as_str()
{
"get_weather" =>
{
let result = json!({
"location": "Tokyo",
"temperature": 18,
"conditions": "Partly cloudy",
"humidity": 65
});
Ok( ToolResult::new( call.id, &result ) )
}
"get_time" =>
{
let result = json!({
"timezone": "Europe/London",
"time": "14:30 GMT",
"date": "2025-11-08"
});
Ok( ToolResult::new( call.id, &result ) )
}
"get_stock_price" =>
{
let result = json!({
"symbol": "AAPL",
"price": 189.50,
"change": "+2.30",
"percent_change": "+1.23%"
});
Ok( ToolResult::new( call.id, &result ) )
}
_ =>
{
Err( format!( "Unknown function : {}", call.function.name ).into() )
}
}
}
).await;
let elapsed = start.elapsed();
println!( "â
Executed {} tool calls in {:?}\n", results.len(), elapsed );
println!( "đ Tool Results:" );
for ( i, result ) in results.iter().enumerate()
{
match result
{
Ok( tool_result ) =>
{
println!( " {}. {} â", i + 1, tool_result.tool_call_id );
println!( " {}\n", tool_result.result );
}
Err( e ) =>
{
println!( " {}. â Error : {}\n", i + 1, e );
}
}
}
let mut messages = vec![
Message::user( "What's the weather in Tokyo, the current time in London, and Apple's stock price?" ),
choice.message.clone(),
];
for tool_result in results.iter().flatten()
{
messages.push( Message::tool(
&tool_result.tool_call_id,
tool_result.result.clone()
) );
}
println!( "đ¤ Sending tool results to model...\n" );
let followup_request = ChatCompletionRequest::former()
.model( "grok-2-1212".to_string() )
.messages( messages )
.tools( vec![ weather_tool, time_tool, stock_tool ] )
.form();
let followup_response = client.chat().create( followup_request ).await?;
if let Some( final_choice ) = followup_response.choices.first()
{
if let Some( ref content ) = final_choice.message.content
{
println!( "đ¤ Final Response:\n {content}\n" );
}
}
println!( "đĄ Performance Benefit:" );
println!( " - Parallel execution : ~{elapsed:?}" );
#[ allow( clippy::cast_possible_truncation ) ] let sequential_time = elapsed * tool_calls.len() as u32;
println!( " - Sequential would take : ~{sequential_time:?}" );
println!( " - Speedup : ~{}x faster\n", tool_calls.len() );
}
else if let Some( ref content ) = choice.message.content
{
println!( "âšī¸ Model responded directly without using tools:\n {content}\n" );
}
}
Ok( () )
}