The Rust SDK is currently in alpha. The API is stable, but some features and interfaces may change based on user feedback.
The DeepResearch API performs comprehensive async research tasks, generating detailed reports with citations from multiple sources. Itβs ideal for in-depth analysis that requires searching, synthesizing, and organizing information from various sources.
Basic Usage
use valyu::ValyuClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = ValyuClient::new("your-api-key");
// Create a simple research task
let task = client.research("What are the key differences between RAG and fine-tuning?").await?;
println!("Task created: {:?}", task.deepresearch_id);
println!("Status: {:?}", task.status);
// Wait for completion
let result = client.deepresearch_wait(
task.deepresearch_id.as_ref().unwrap(),
5, // Poll every 5 seconds
900, // Timeout after 15 minutes
).await?;
if let Some(output) = &result.output {
println!("Research output: {}", output);
}
Ok(())
}
Advanced Usage with Builder Pattern
Use DeepResearchCreateRequest for full control over the research task:
use valyu::{DeepResearchCreateRequest, DeepResearchMode, ValyuClient};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = ValyuClient::new("your-api-key");
let request = DeepResearchCreateRequest::new(
"What are the key differences between RAG and fine-tuning for LLMs?"
)
.with_mode(DeepResearchMode::Lite)
.with_output_formats(vec!["markdown".to_string(), "pdf".to_string()])
.with_strategy("Focus on peer-reviewed sources and recent publications");
let task = client.deepresearch_create(&request).await?;
println!("Task created: {:?}", task.deepresearch_id);
// Wait for completion with custom timeout
let result = client.deepresearch_wait(
task.deepresearch_id.as_ref().unwrap(),
5, // Poll every 5 seconds
900, // Timeout after 15 minutes
).await?;
// Access the research output
if let Some(output) = &result.output {
println!("Research completed!");
println!("{}", output);
}
// Access sources used
if let Some(sources) = &result.sources {
println!("\nSources ({}):", sources.len());
for source in sources.iter().take(5) {
println!(" - {} ({})", source.title, source.url);
}
}
// Access cost breakdown
if let Some(usage) = &result.usage {
println!("\nCost breakdown:");
println!(" Search: ${:.4}", usage.search_cost);
println!(" Contents: ${:.4}", usage.contents_cost);
println!(" AI: ${:.4}", usage.ai_cost);
println!(" Total: ${:.4}", usage.total_cost);
}
// PDF download URL (if requested)
if let Some(pdf_url) = &result.pdf_url {
println!("\nPDF Report: {}", pdf_url);
}
Ok(())
}
Research Modes
| Mode | Use Case | Typical Completion Time | Cost |
|---|
Fast | Quick answers, lightweight research, simple lookups | ~5 minutes | $0.15 |
Lite | Balanced research, deeper insights without long wait times | ~10-20 minutes | $0.50 |
Heavy | In-depth, long-running research tasks, complex analysis | Up to ~90 minutes | $1.50 |
use valyu::DeepResearchMode;
// Fast mode for quick lookups
let request = DeepResearchCreateRequest::new("What is quantum computing?")
.with_mode(DeepResearchMode::Fast);
// Lite mode for moderate research
let request = DeepResearchCreateRequest::new("Compare React and Vue frameworks")
.with_mode(DeepResearchMode::Lite);
// Heavy mode for comprehensive analysis
let request = DeepResearchCreateRequest::new("Analyze the impact of AI on healthcare")
.with_mode(DeepResearchMode::Heavy);
Parameters
| Parameter | Type | Description |
|---|
input | impl Into<String> | Research query or task description |
Builder Methods (Optional)
| Method | Type | Description | Default |
|---|
with_mode() | DeepResearchMode | Research mode: Fast, Lite, or Heavy | Lite |
with_output_formats() | Vec<String> | Output formats: ["markdown"], ["markdown", "pdf"] | ["markdown"] |
with_structured_output() | serde_json::Value | JSON schema for structured output | None |
with_strategy() | impl Into<String> | Natural language research strategy | None |
with_search() | DeepResearchSearchConfig | Search configuration | None |
with_urls() | Vec<String> | URLs to extract content from (max 10) | None |
with_files() | Vec<DeepResearchFileAttachment> | File attachments (max 10) | None |
with_mcp_servers() | Vec<DeepResearchMCPServerConfig> | MCP server configs (max 5) | None |
with_code_execution() | bool | Enable/disable code execution | true |
with_previous_reports() | Vec<String> | Previous report IDs for context (max 3) | None |
with_webhook_url() | impl Into<String> | Webhook URL for completion notification | None |
with_metadata() | serde_json::Value | Custom metadata | None |
Response Types
DeepResearchCreateResponse
pub struct DeepResearchCreateResponse {
pub success: bool,
pub deepresearch_id: Option<String>,
pub status: Option<DeepResearchStatus>,
pub model: Option<DeepResearchMode>,
pub created_at: Option<String>,
pub metadata: Option<serde_json::Value>,
pub public: Option<bool>,
pub webhook_secret: Option<String>, // Only returned once - store securely!
pub message: Option<String>,
pub error: Option<String>,
}
DeepResearchStatusResponse
pub struct DeepResearchStatusResponse {
pub success: bool,
pub deepresearch_id: Option<String>,
pub status: Option<DeepResearchStatus>, // Queued, Running, Completed, Failed, Cancelled
pub query: Option<String>,
pub mode: Option<DeepResearchMode>,
pub output_formats: Option<Vec<serde_json::Value>>,
pub created_at: Option<i64>,
pub public: Option<bool>,
pub progress: Option<DeepResearchProgress>, // Current step / total steps
pub messages: Option<Vec<serde_json::Value>>,
pub completed_at: Option<i64>,
pub output: Option<serde_json::Value>, // Research output (markdown or JSON)
pub output_type: Option<String>, // "markdown" or "json"
pub pdf_url: Option<String>, // PDF download URL
pub images: Option<Vec<DeepResearchImage>>, // Generated charts/images
pub sources: Option<Vec<DeepResearchSource>>, // Sources used
pub usage: Option<DeepResearchUsage>, // Cost breakdown
pub error: Option<String>,
}
pub struct DeepResearchProgress {
pub current_step: i32,
pub total_steps: i32,
}
pub struct DeepResearchUsage {
pub search_cost: f64,
pub contents_cost: f64,
pub ai_cost: f64,
pub compute_cost: f64,
pub total_cost: f64,
}
Client Methods
Create Task
let task = client.deepresearch_create(&request).await?;
Get Status
let status = client.deepresearch_status("task-id").await?;
println!("Current status: {:?}", status.status);
if let Some(progress) = &status.progress {
println!("Progress: {}/{}", progress.current_step, progress.total_steps);
}
Wait for Completion
// Wait with custom polling interval and timeout
let result = client.deepresearch_wait(
"task-id",
5, // Poll every 5 seconds
900, // Timeout after 15 minutes
).await?;
List Tasks
let tasks = client.deepresearch_list("api-key-id", Some(50)).await?;
if let Some(data) = &tasks.data {
for task in data {
println!("{}: {:?} - {}", task.deepresearch_id, task.status, task.query);
}
}
Cancel Task
client.deepresearch_cancel("task-id").await?;
Delete Task
client.deepresearch_delete("task-id").await?;
Use Case Examples
Academic Research
use valyu::{DeepResearchCreateRequest, DeepResearchMode, DeepResearchSearchConfig};
let request = DeepResearchCreateRequest::new(
"What are the latest advances in quantum error correction?"
)
.with_mode(DeepResearchMode::Heavy)
.with_output_formats(vec!["markdown".to_string(), "pdf".to_string()])
.with_strategy("Focus on peer-reviewed papers from 2023-2024. Include citations.")
.with_search(DeepResearchSearchConfig {
search_type: Some("proprietary".to_string()),
included_sources: Some(vec!["valyu/valyu-arxiv".to_string()]),
});
let task = client.deepresearch_create(&request).await?;
let result = client.deepresearch_wait(
task.deepresearch_id.as_ref().unwrap(),
10, // Poll every 10 seconds (heavy mode takes longer)
5400, // 90 minute timeout for heavy mode
).await?;
Market Analysis
use serde_json::json;
let schema = json!({
"type": "object",
"properties": {
"market_overview": {"type": "string"},
"key_players": {
"type": "array",
"items": {
"type": "object",
"properties": {
"company": {"type": "string"},
"market_share": {"type": "string"},
"strengths": {"type": "array", "items": {"type": "string"}}
}
}
},
"trends": {"type": "array", "items": {"type": "string"}},
"forecast": {"type": "string"}
}
});
let request = DeepResearchCreateRequest::new(
"Analyze the AI chip market landscape in 2024"
)
.with_mode(DeepResearchMode::Lite)
.with_structured_output(schema);
let task = client.deepresearch_create(&request).await?;
Research with File Attachments
use valyu::DeepResearchFileAttachment;
use base64;
use std::fs;
// Read and encode a PDF file
let pdf_bytes = fs::read("research_paper.pdf")?;
let pdf_base64 = base64::encode(&pdf_bytes);
let request = DeepResearchCreateRequest::new(
"Summarize the key findings from this research paper and compare with recent literature"
)
.with_mode(DeepResearchMode::Lite)
.with_files(vec![DeepResearchFileAttachment {
data: format!("data:application/pdf;base64,{}", pdf_base64),
filename: "research_paper.pdf".to_string(),
media_type: "application/pdf".to_string(),
context: Some("Primary research paper to analyze".to_string()),
}]);
let task = client.deepresearch_create(&request).await?;
Webhook Integration
let request = DeepResearchCreateRequest::new("Comprehensive AI safety research")
.with_mode(DeepResearchMode::Heavy)
.with_webhook_url("https://your-app.com/webhooks/deepresearch");
let task = client.deepresearch_create(&request).await?;
// Store the webhook secret securely for signature verification
if let Some(secret) = &task.webhook_secret {
println!("Webhook secret (store securely): {}", secret);
}
Error Handling
use valyu::{ValyuClient, DeepResearchCreateRequest, ValyuError};
let request = DeepResearchCreateRequest::new("test query");
match client.deepresearch_create(&request).await {
Ok(task) => {
if !task.success {
eprintln!("Task creation failed: {:?}", task.error);
return Ok(());
}
println!("Task created: {:?}", task.deepresearch_id);
}
Err(ValyuError::InvalidApiKey) => eprintln!("Invalid API key"),
Err(ValyuError::ApiError(msg)) if msg.contains("Insufficient credits") => {
eprintln!("Not enough credits - please top up your account");
}
Err(ValyuError::RateLimitExceeded) => eprintln!("Rate limit exceeded"),
Err(e) => eprintln!("Error: {}", e),
}
// Handle wait errors
match client.deepresearch_wait("task-id", 5, 900).await {
Ok(result) => {
println!("Research completed: {:?}", result.status);
}
Err(ValyuError::ApiError(msg)) if msg.contains("Task was cancelled") => {
eprintln!("Task was cancelled");
}
Err(ValyuError::ApiError(msg)) if msg.contains("exceeded") => {
eprintln!("Task timed out - consider using a longer timeout for heavy mode");
}
Err(e) => eprintln!("Error: {}", e),
}
Best Practices
Choose the Right Mode
// Fast mode: Quick factual lookups
let request = DeepResearchCreateRequest::new("What year was Python released?")
.with_mode(DeepResearchMode::Fast);
// Lite mode: Standard research questions
let request = DeepResearchCreateRequest::new("Compare Python vs Rust for systems programming")
.with_mode(DeepResearchMode::Lite);
// Heavy mode: Complex multi-faceted analysis
let request = DeepResearchCreateRequest::new(
"Comprehensive analysis of renewable energy adoption across OECD countries"
)
.with_mode(DeepResearchMode::Heavy);
Set Appropriate Timeouts
// Fast mode: 5 minutes
let result = client.deepresearch_wait(task_id, 3, 300).await?;
// Lite mode: 15 minutes
let result = client.deepresearch_wait(task_id, 5, 900).await?;
// Heavy mode: 90 minutes
let result = client.deepresearch_wait(task_id, 10, 5400).await?;
Use Webhooks for Long-Running Tasks
For heavy mode tasks, consider using webhooks instead of polling:
let request = DeepResearchCreateRequest::new("Complex research task")
.with_mode(DeepResearchMode::Heavy)
.with_webhook_url("https://your-app.com/webhooks/research-complete");
let task = client.deepresearch_create(&request).await?;
// Task ID for later reference
println!("Task submitted: {:?}", task.deepresearch_id);
// Handle the webhook callback in your web server
// The webhook will include the task ID and completion status
Handle Progress Updates
let task_id = task.deepresearch_id.as_ref().unwrap();
loop {
let status = client.deepresearch_status(task_id).await?;
match &status.status {
Some(DeepResearchStatus::Running) => {
if let Some(progress) = &status.progress {
println!(
"Progress: Step {}/{}",
progress.current_step, progress.total_steps
);
}
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
}
Some(DeepResearchStatus::Completed) => {
println!("Research completed!");
break;
}
Some(DeepResearchStatus::Failed) => {
eprintln!("Research failed: {:?}", status.error);
break;
}
_ => {
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
}
}
}