use just_deepseek::types::chat::{
ChatCompletionRequest, ChatMessage, FunctionDefinition, ReasoningEffort, ThinkingConfig,
ThinkingMode, ToolCallsMessage, ToolDefinition, ToolType,
};
use just_deepseek::{DeepSeekClient, Error};
fn add(args: &serde_json::Value) -> serde_json::Value {
let x = args["x"].as_f64().expect("x is not a number");
let y = args["y"].as_f64().expect("y is not a number");
serde_json::json!({ "result": x + y })
}
#[tokio::main]
async fn main() -> Result<(), Error> {
dotenvy::dotenv().ok();
let api_key =
std::env::var("JUST_LLM_DEEPSEEK_API_KEY").expect("JUST_LLM_DEEPSEEK_API_KEY must be set");
let base_url = std::env::var("JUST_LLM_DEEPSEEK_BASE_URL").ok();
let model =
std::env::var("JUST_LLM_DEEPSEEK_MODEL").expect("JUST_LLM_DEEPSEEK_MODEL must be set");
let mut builder = DeepSeekClient::builder().api_key(&api_key);
if let Some(url) = base_url {
builder = builder.base_url(&url);
}
let client = builder.build()?;
let add_tool = ToolDefinition {
kind: ToolType::Function,
function: FunctionDefinition {
name: "add".to_owned(),
description: Some("Add two numbers together.".to_owned()),
parameters: Some(serde_json::json!({
"type": "object",
"properties": {
"x": { "type": "number", "description": "The first number." },
"y": { "type": "number", "description": "The second number." }
},
"required": ["x", "y"]
})),
strict: None,
},
};
let system_prompt = "You are a helpful math assistant. Use the provided tools.";
let user_prompt = "What is 12345 + 67890?";
let mut request = ChatCompletionRequest::new(
model,
vec![
ChatMessage::system(system_prompt),
ChatMessage::user(user_prompt),
],
);
request.tools = Some(vec![add_tool]);
request.thinking = Some(ThinkingConfig {
kind: ThinkingMode::Enabled,
});
request.reasoning_effort = Some(ReasoningEffort::High);
println!("--- request 1 ---");
println!(" [system] {system_prompt}");
println!(" [user] {user_prompt}");
let completion = client.chat_completion(request).await?;
let choice = completion
.choices
.first()
.expect("expected at least one choice");
let reasoning = choice.message.reasoning_content.clone();
let tool_calls = choice
.message
.tool_calls
.as_ref()
.expect("expected tool calls in response");
println!("\n--- response 1 ---");
if let Some(r) = &reasoning {
println!(" [reasoning] {r}");
}
let call = &tool_calls[0];
println!(
" [tool call] {}({})",
call.function.name, call.function.arguments
);
let args: serde_json::Value = serde_json::from_str(&call.function.arguments)?;
let tool_result = add(&args);
println!("\n--- tool result ---");
println!(" {tool_result}");
let assistant_msg = ChatMessage::ToolCalls(ToolCallsMessage {
role: "assistant".to_owned(),
content: None,
name: None,
tool_calls: tool_calls.clone(),
reasoning_content: reasoning,
});
let request2 = ChatCompletionRequest::new(
completion.model,
vec![
ChatMessage::system(system_prompt),
ChatMessage::user(user_prompt),
assistant_msg,
ChatMessage::tool_result(tool_result.to_string(), &call.id),
],
);
let final_completion = client.chat_completion(request2).await?;
println!("\n--- response 2 ---");
if let Some(choice) = final_completion.choices.first() {
if let Some(r) = &choice.message.reasoning_content {
println!(" [reasoning] {r}");
}
println!(
" [assistant] {}",
choice.message.content.as_deref().unwrap_or_default()
);
}
if let Some(usage) = &final_completion.usage {
println!(
" [usage] prompt={} completion={} total={}",
usage.prompt_tokens, usage.completion_tokens, usage.total_tokens
);
}
Ok(())
}