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::Standard)
.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(cost) = &result.cost {
println!("\nCost: ${:.4}", 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.10 |
Standard | 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 | $2.50 |
Max | Exhaustive research with maximum quality and fact verification | Up to ~180 minutes | $15.00 |
In Rust, use the enum variants DeepResearchMode::Fast, DeepResearchMode::Lite, DeepResearchMode::Heavy, and DeepResearchMode::Max. The Lite variant corresponds to the standard mode in the API (backward compatible).
use valyu::DeepResearchMode;
// Fast mode for quick lookups
let request = DeepResearchCreateRequest::new("What is quantum computing?")
.with_mode(DeepResearchMode::Fast);
// Standard mode for moderate research
let request = DeepResearchCreateRequest::new("Compare React and Vue frameworks")
.with_mode(DeepResearchMode::Standard);
// 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, Standard, or Heavy | Standard |
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_deliverables() | Vec<serde_json::Value> | Additional file outputs to generate (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 |
Search Configuration
Search parameters control which data sources are queried, what content is included/excluded, and how results are filtered by date or category. These parameters are specified using DeepResearchSearchConfig and passed to the request via with_search().
Overview
Search parameters allow you to:
- Control which backend search systems are queried (
search_type)
- Restrict or exclude specific source types (
included_sources, excluded_sources)
- Filter results by publication date (
start_date, end_date)
- Filter by category (
category)
Basic Example
use valyu::{DeepResearchCreateRequest, DeepResearchMode, DeepResearchSearchConfig};
let request = DeepResearchCreateRequest::new(
"Latest AI research in healthcare diagnostics"
)
.with_mode(DeepResearchMode::Heavy)
.with_search(DeepResearchSearchConfig {
search_type: Some("all".to_string()),
included_sources: Some(vec!["academic".to_string(), "web".to_string()]),
start_date: Some("2024-01-01".to_string()),
end_date: Some("2024-12-31".to_string()),
excluded_sources: None,
category: None,
});
Search Type
Controls which backend search systems are queried:
"all" (default): Searches both web and proprietary data sources
"web": Searches only web sources (general web search, news, articles)
"proprietary": Searches only proprietary data sources (academic papers, finance data, patents, etc.)
When set at the request level, this parameter cannot be overridden by the AI agent during research.
let request = DeepResearchCreateRequest::new(
"Recent advances in quantum computing"
)
.with_search(DeepResearchSearchConfig {
search_type: Some("proprietary".to_string()),
..Default::default()
});
Included Sources
Restricts search to only the specified source types. When specified, only these sources will be searched. If the AI agent attempts to use other sources, they will be ignored.
Available source types:
"web": General web search results (news, articles, websites)
"academic": Academic papers and research databases (ArXiv, PubMed, BioRxiv/MedRxiv, Clinical trials, FDA drug labels, WHO health data, NIH grants, Wikipedia)
"finance": Financial and economic data (Stock/crypto/FX prices, SEC filings, Company financial statements, Economic indicators, Prediction markets)
"patent": Patent and intellectual property data (USPTO patent database, Patent abstracts, claims, descriptions)
"transportation": Transit and transportation data (UK National Rail schedules, Maritime vessel tracking)
"politics": Government and parliamentary data (UK Parliament members, bills, votes)
"legal": Case law and legal data (UK court judgments, Legislation text)
let request = DeepResearchCreateRequest::new(
"Latest AI research"
)
.with_search(DeepResearchSearchConfig {
search_type: Some("proprietary".to_string()),
included_sources: Some(vec!["academic".to_string(), "web".to_string()]),
..Default::default()
});
Excluded Sources
Excludes specific source types from search results. Uses the same source type values as included_sources. Cannot be used simultaneously with included_sources (use one or the other).
let request = DeepResearchCreateRequest::new(
"Clinical trial results"
)
.with_search(DeepResearchSearchConfig {
search_type: Some("proprietary".to_string()),
excluded_sources: Some(vec!["web".to_string(), "patent".to_string()]),
..Default::default()
});
Start Date
Format: ISO date format (YYYY-MM-DD)
Filters search results to only include content published or dated on or after this date. Applied to both publication dates and event dates when available. Works across all source types.
let request = DeepResearchCreateRequest::new(
"Recent AI developments"
)
.with_search(DeepResearchSearchConfig {
start_date: Some("2024-01-01".to_string()),
..Default::default()
});
End Date
Format: ISO date format (YYYY-MM-DD)
Filters search results to only include content published or dated on or before this date. Applied to both publication dates and event dates when available. Works across all source types.
let request = DeepResearchCreateRequest::new(
"Historical market analysis"
)
.with_search(DeepResearchSearchConfig {
end_date: Some("2020-12-31".to_string()),
..Default::default()
});
Category
Filters results by a specific category. The exact categories available depend on the data source. Category values are source-dependent and may not be applicable to all source types.
let request = DeepResearchCreateRequest::new(
"Technology trends"
)
.with_search(DeepResearchSearchConfig {
category: Some("technology".to_string()),
..Default::default()
});
Important Notes
Parameter Enforcement
Request-level parameters are enforced and cannot be overridden by the AI agent during research. This ensures consistent search behavior throughout the research process. Tool-level source specifications are ignored if request-level sources are specified.
Date Filtering
Dates are applied to both publication dates and event dates when available. ISO format (YYYY-MM-DD) is required. Date filtering works across all source types. If only start_date is provided, results include all content from that date forward. If only end_date is provided, results include all content up to that date. Both dates can be combined for a specific date range.
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 deliverables: Option<Vec<DeliverableResult>>, // Generated deliverable files
pub sources: Option<Vec<DeepResearchSource>>, // Sources used
pub cost: Option<f64>, // Fixed cost for the task
pub error: Option<String>,
}
pub struct DeepResearchProgress {
pub current_step: i32,
pub total_steps: i32,
}
// Cost is a simple f64 value representing the fixed price:
// - Fast: $0.10
// - Standard: $0.50
// - Heavy: $2.00
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::Standard)
.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_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?;
Research with Deliverables
Generate additional file outputs alongside the research report:
use valyu::{Deliverable, DeliverableType};
use serde_json::json;
// Simple deliverables using strings
let request = DeepResearchCreateRequest::new(
"Research the top 20 AI companies in 2024"
)
.with_deliverables(vec![
json!("CSV file with company names, founding year, and funding"),
json!("PowerPoint presentation with 5 slides summarizing key findings")
]);
let task = client.deepresearch_create(&request).await?;
let result = client.deepresearch_wait(&task.deepresearch_id.unwrap()).await?;
// Access deliverables
if let Some(deliverables) = &result.deliverables {
for deliverable in deliverables {
if deliverable.status == DeliverableStatus::Completed {
println!("✅ {}", deliverable.title);
println!(" Download: {}", deliverable.url);
if let Some(rows) = deliverable.row_count {
println!(" Rows: {}", rows);
}
}
}
}
Structured Deliverables
Use the Deliverable type for precise control:
use valyu::{Deliverable, DeliverableType};
use serde_json::json;
let request = DeepResearchCreateRequest::new(
"Analyze startup funding trends in 2024"
)
.with_deliverables(vec![
json!(Deliverable {
deliverable_type: DeliverableType::Xlsx,
description: "Startup funding data with company details".to_string(),
columns: Some(vec![
"Company".to_string(),
"Funding Amount".to_string(),
"Date".to_string(),
"Investors".to_string(),
"Stage".to_string()
]),
include_headers: Some(true),
sheet_name: Some("Funding Data".to_string()),
slides: None,
template: None,
}),
json!(Deliverable {
deliverable_type: DeliverableType::Pptx,
description: "Executive summary presentation".to_string(),
columns: None,
include_headers: None,
sheet_name: None,
slides: Some(10),
template: Some("modern".to_string()),
}),
json!(Deliverable {
deliverable_type: DeliverableType::Pdf,
description: "Detailed analysis report with charts and insights".to_string(),
columns: None,
include_headers: None,
sheet_name: None,
slides: None,
template: None,
})
]);
let task = client.deepresearch_create(&request).await?;
let result = client.deepresearch_wait(&task.deepresearch_id.unwrap()).await?;
// Process deliverables
if let Some(deliverables) = &result.deliverables {
for deliverable in deliverables {
println!("{}: {}", deliverable.deliverable_type.to_uppercase(), deliverable.title);
println!("Status: {:?}", deliverable.status);
match deliverable.status {
DeliverableStatus::Completed => {
println!("Download: {}", deliverable.url);
}
DeliverableStatus::Failed => {
if let Some(error) = &deliverable.error {
println!("Error: {}", error);
}
}
}
}
}
You can request up to 10 deliverables per research task. Deliverables are generated after the research completes.
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);
// Standard mode: Standard research questions
let request = DeepResearchCreateRequest::new("Compare Python vs Rust for systems programming")
.with_mode(DeepResearchMode::Standard);
// 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?;
// Standard 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;
}
}
}