Skip to main content
The Rust SDK is in alpha. The API is stable, but some interfaces may change based on feedback.
DeepResearch plans, searches, verifies, and writes a cited report. Tasks run async - create one, then poll or wait for the result.
For the conceptual overview, search configuration, and best practices, see the DeepResearch Guide. This page is the Rust SDK method reference.

Wire up Valyu DeepResearch (autonomous research agent) with the Rust SDK (alpha).

Open in Cursor

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 task (defaults to standard mode)
    let task = client.research("What are the key differences between RAG and fine-tuning?").await?;

    // Wait for completion - (task_id, poll_interval_secs, timeout_secs)
    let result = client.deepresearch_wait(
        task.deepresearch_id.as_ref().unwrap(),
        5,
        900,
    ).await?;

    if let Some(output) = &result.output {
        println!("{}", output);
    }
    if let Some(cost) = &result.cost {
        println!("Cost: ${:.4}", cost);
    }

    Ok(())
}

Research modes

ModeBest forTypical timePrice
FastQuick lookups, lightweight research~5 min$0.10
StandardBalanced research (default)~10-20 min$0.50
HeavyIn-depth, complex analysisup to ~90 min$2.50
MaxExhaustive research with fact verificationup to ~180 min$15.00
Use the enum variants DeepResearchMode::Fast, ::Standard, ::Heavy, ::Max. The legacy ::Lite variant maps to standard. Max requires at least $15 in available credits.

Builder pattern

Use DeepResearchCreateRequest for full control, then call client.deepresearch_create(&request):
use valyu::{DeepResearchCreateRequest, DeepResearchMode};

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.");

let task = client.deepresearch_create(&request).await?;
let result = client.deepresearch_wait(
    task.deepresearch_id.as_ref().unwrap(),
    10,   // poll every 10s (heavy mode takes longer)
    5400, // 90-minute timeout
).await?;

if let Some(pdf_url) = &result.pdf_url {
    println!("PDF report: {}", pdf_url);
}
In production, prefer webhooks over polling. The webhook_secret is returned only once on create - store it securely:
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?;
if let Some(secret) = &task.webhook_secret {
    // store securely - not retrievable later
}

Reference

input (impl Into<String>, required) - research query or task description.
MethodTypeDescriptionDefault
with_mode()DeepResearchModeResearch modeStandard
with_output_formats()Vec<String>["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 config (see below)None
with_urls()Vec<String>URLs to analyze (max 10)None
with_files()Vec<DeepResearchFileAttachment>File attachments (max 10)None
with_deliverables()Vec<serde_json::Value>Additional file outputs (max 10)None
with_mcp_servers()Vec<DeepResearchMCPServerConfig>MCP server configs (max 5)None
with_code_execution()boolEnable 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
DeepResearchSearchConfig (passed via with_search()) controls which sources are queried. Request-level parameters are enforced and cannot be overridden by the agent.
use valyu::{DeepResearchCreateRequest, DeepResearchSearchConfig};

let request = DeepResearchCreateRequest::new("Latest AI research in healthcare diagnostics")
    .with_search(DeepResearchSearchConfig {
        included_sources: Some(vec!["academic".to_string(), "web".to_string()]),
        start_date: Some("2024-01-01".to_string()),    // YYYY-MM-DD
        end_date: Some("2024-12-31".to_string()),
        excluded_sources: None,                         // use included OR excluded, not both
        category: None,
    });
Source types: web, academic, finance, patent, transportation, politics, legal. Date filters apply to both publication and event dates. See the DeepResearch Guide for full detail.
use valyu::DeepResearchFileAttachment;
use serde_json::json;

let pdf_base64 = base64::encode(&std::fs::read("paper.pdf")?);

let request = DeepResearchCreateRequest::new("Summarize this paper and compare with recent literature")
    .with_files(vec![DeepResearchFileAttachment {
        data: format!("data:application/pdf;base64,{}", pdf_base64),
        filename: "paper.pdf".to_string(),
        media_type: "application/pdf".to_string(),
        context: Some("Primary research paper".to_string()),
    }])
    .with_deliverables(vec![
        json!("CSV file with company names, founding year, and funding"),
        json!("PowerPoint presentation with 5 slides"),
    ]);

let result = client.deepresearch_wait(
    task.deepresearch_id.as_ref().unwrap(), 10, 5400,
).await?;

for d in result.deliverables.as_deref().unwrap_or(&[]) {
    if d.status == DeliverableStatus::Completed {
        println!("{}: {}", d.title, d.url);
    }
}
Up to 10 deliverables per task (csv, xlsx, pptx, docx, pdf), generated after research completes. Supported file types: PDFs, images (PNG, JPEG, WebP), and documents.
client.deepresearch_create(&request).await?;
client.deepresearch_status("task-id").await?;             // status + progress
client.deepresearch_wait("task-id", 5, 900).await?;       // (id, poll_secs, timeout_secs)
client.deepresearch_list("api-key-id", Some(50)).await?;
client.deepresearch_cancel("task-id").await?;
client.deepresearch_delete("task-id").await?;
pub struct DeepResearchCreateResponse {
    pub success: bool,
    pub deepresearch_id: Option<String>,
    pub status: Option<DeepResearchStatus>,
    pub created_at: Option<String>,
    pub webhook_secret: Option<String>,  // Only returned once - store securely
    pub error: Option<String>,
    // ... other optional fields
}

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 progress: Option<DeepResearchProgress>,  // current_step / total_steps
    pub output: Option<serde_json::Value>,
    pub output_type: Option<String>,             // "markdown" | "json"
    pub pdf_url: Option<String>,
    pub images: Option<Vec<DeepResearchImage>>,
    pub deliverables: Option<Vec<DeliverableResult>>,
    pub sources: Option<Vec<DeepResearchSource>>,
    pub cost: Option<f64>,
    pub error: Option<String>,
    // ... other optional fields
}
use valyu::{DeepResearchCreateRequest, ValyuError};

match client.deepresearch_create(&DeepResearchCreateRequest::new("test query")).await {
    Ok(task) if task.success => println!("Created: {:?}", task.deepresearch_id),
    Ok(task) => eprintln!("Failed: {:?}", task.error),
    Err(ValyuError::InvalidApiKey) => eprintln!("Invalid API key"),
    Err(ValyuError::ApiError(msg)) if msg.contains("Insufficient credits") => {
        eprintln!("Not enough credits - please top up");
    }
    Err(ValyuError::RateLimitExceeded) => eprintln!("Rate limit exceeded"),
    Err(e) => eprintln!("Error: {}", e),
}
deepresearch_wait errors when the task is cancelled or the timeout is exceeded - use a longer timeout for heavy/max mode.