Skip to main content
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

ModeUse CaseTypical Completion TimeCost
FastQuick answers, lightweight research, simple lookups~5 minutes$0.15
LiteBalanced research, deeper insights without long wait times~10-20 minutes$0.50
HeavyIn-depth, long-running research tasks, complex analysisUp 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

Input (Required)

ParameterTypeDescription
inputimpl Into<String>Research query or task description

Builder Methods (Optional)

MethodTypeDescriptionDefault
with_mode()DeepResearchModeResearch mode: Fast, Lite, or HeavyLite
with_output_formats()Vec<String>Output formats: ["markdown"], ["markdown", "pdf"]["markdown"]
with_structured_output()serde_json::ValueJSON schema for structured outputNone
with_strategy()impl Into<String>Natural language research strategyNone
with_search()DeepResearchSearchConfigSearch configurationNone
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()boolEnable/disable code executiontrue
with_previous_reports()Vec<String>Previous report IDs for context (max 3)None
with_webhook_url()impl Into<String>Webhook URL for completion notificationNone
with_metadata()serde_json::ValueCustom metadataNone

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;
        }
    }
}