Skip to content

valyu-network/valyu-rust

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Valyu Rust SDK

Crates.io Documentation License Alpha

Official Rust SDK for the Valyu AI API.

Search for AIs - Valyu's Deepsearch API gives AI the context it needs. Integrate trusted, high-quality public and proprietary sources, with full-text multimodal retrieval.

Get $10 free credits for the Valyu API when you sign up at platform.valyu.ai! No credit card required.

⚠️ Alpha Release: This SDK is currently in alpha. The API is stable, but some features and interfaces may change based on user feedback. We welcome your input!

How Does It Work?

We do all the heavy lifting for you - one unified API for all data:

  • Academic & Research Content - Access millions of scholarly papers, journals, and textbooks
  • Real-time Web Search - Get the latest information from across the internet
  • Medical Literature - Peer-reviewed studies, clinical trials, and regulatory documents
  • Structured Financial Data - Stock prices, market data, and financial metrics
  • Intelligent Reranking - Results across all sources are automatically sorted by relevance
  • Transparent Pricing - Pay only for what you use with clear CPM (cost per thousand) pricing

Features

  • Type-safe API: Full type coverage with serde support for all API endpoints
  • Async/await: Built on tokio and reqwest for efficient async operations
  • Builder pattern: Fluent interface for constructing complex search requests
  • Comprehensive error handling: Detailed error types for all failure scenarios
  • Three powerful endpoints: DeepSearch, Contents, and Answer APIs
  • Well documented: Extensive documentation with examples for all features
  • Production ready: Designed for reliability and ease of use in production environments

Installation

Add this to your Cargo.toml:

[dependencies]
valyu = "0.1"
tokio = { version = "1", features = ["full"] }

Get your API key from platform.valyu.ai.

Quick Start

Basic Usage

use valyu::ValyuClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a client with your API key
    let client = ValyuClient::new("your-api-key");

    // Perform a simple search
    let response = client.search("quantum computing").await?;

    // Process results
    if let Some(results) = &response.results {
        for result in results {
            println!("{}: {}",
                result.title.as_deref().unwrap_or("Untitled"),
                result.url.as_deref().unwrap_or("No URL")
            );
        }
    }

    Ok(())
}

Advanced Usage with Builder Pattern

use valyu::{ValyuClient, DeepSearchRequest};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = ValyuClient::new("your-api-key");

    // Build a custom search request with specific parameters
    let request = DeepSearchRequest::new("artificial intelligence")
        .with_max_results(10)
        .with_search_type("web")
        .with_fast_mode(true)
        .with_response_length("medium")
        .with_relevance_threshold(0.7)
        .with_date_range("2024-01-01", "2024-12-31");

    let response = client.deep_search(&request).await?;

    println!("Transaction ID: {}", response.tx_id.as_deref().unwrap_or("N/A"));
    println!("Cost: ${:.4}", response.total_deduction_dollars.unwrap_or(0.0));

    Ok(())
}

Authentication

Set your API key in one of these ways:

Environment Variable (Recommended)

export VALYU_API_KEY="your-api-key-here"

Then in your code:

use std::env;
use valyu::ValyuClient;

let api_key = env::var("VALYU_API_KEY").expect("VALYU_API_KEY must be set");
let client = ValyuClient::new(api_key);

Direct Initialization

use valyu::ValyuClient;

let client = ValyuClient::new("your-api-key-here");

Using .env File

For local development, use the dotenvy crate:

[dependencies]
dotenvy = "0.15"
use std::env;
use valyu::ValyuClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    dotenvy::dotenv().ok();
    let api_key = env::var("VALYU_API_KEY")?;
    let client = ValyuClient::new(api_key);
    Ok(())
}

Error Handling

The SDK uses a custom ValyuError type for detailed error handling:

use valyu::{ValyuClient, ValyuError};

#[tokio::main]
async fn main() {
    let client = ValyuClient::new("your-api-key");

    match client.search("test").await {
        Ok(response) => {
            if response.success {
                println!("Success! Found {} results",
                    response.results.as_ref().map(|r| r.len()).unwrap_or(0));
            } else {
                eprintln!("API returned error: {:?}", response.error);
            }
        }
        Err(ValyuError::InvalidApiKey) => eprintln!("Invalid API key provided"),
        Err(ValyuError::RateLimitExceeded) => eprintln!("Rate limit exceeded - please retry later"),
        Err(ValyuError::ServiceUnavailable) => eprintln!("Service temporarily unavailable"),
        Err(ValyuError::InvalidRequest(msg)) => eprintln!("Invalid request: {}", msg),
        Err(e) => eprintln!("Error: {}", e),
    }
}

Custom HTTP Client Configuration

use valyu::ValyuClient;
use std::time::Duration;

let http_client = reqwest::Client::builder()
    .timeout(Duration::from_secs(30))
    .build()
    .unwrap();

let client = ValyuClient::with_client("your-api-key", http_client);

API Reference

ValyuClient

The main client for interacting with the Valyu API.

Methods

  • new(api_key: impl Into<String>) -> Self - Create a new client with an API key
  • with_base_url(api_key, base_url) -> Self - Create client with custom base URL
  • with_client(api_key, reqwest::Client) -> Self - Create client with custom HTTP client
  • search(query: impl Into<String>) -> Result<DeepSearchResponse> - Simple search with default settings
  • deep_search(request: &DeepSearchRequest) -> Result<DeepSearchResponse> - Advanced search with custom parameters
  • contents(request: &ContentsRequest) -> Result<ContentsResponse> - Extract content from URLs
  • answer(request: &AnswerRequest) -> Result<AnswerResponse> - Get AI-powered answers
  • ask(query: impl Into<String>) -> Result<AnswerResponse> - Simple answer with defaults

DeepSearchRequest

Builder for constructing search requests with optional parameters.

Constructor

  • new(query: impl Into<String>) -> Self - Create a new request with just a query

Builder Methods

  • with_max_results(max: u8) -> Self - Set max results (1-20)
  • with_search_type(type: impl Into<String>) -> Self - Set search type: "all", "web", or "proprietary"
  • with_fast_mode(enabled: bool) -> Self - Enable fast mode for reduced latency
  • with_response_length(length: impl Into<String>) -> Self - Set response length: "short", "medium", "large", or "max"
  • with_relevance_threshold(threshold: f64) -> Self - Set relevance threshold (0.0-1.0)
  • with_included_sources(sources: Vec<String>) -> Self - Specify sources to include
  • with_excluded_sources(sources: Vec<String>) -> Self - Specify sources to exclude
  • with_date_range(start: impl Into<String>, end: impl Into<String>) -> Self - Set date range (YYYY-MM-DD format)
  • with_max_price(price: f64) -> Self - Set maximum CPM price
  • with_category(category: impl Into<String>) -> Self - Set category filter
  • with_country_code(code: impl Into<String>) -> Self - Set country code (2-letter ISO)
  • with_is_tool_call(is_tool_call: bool) -> Self - Set whether this is a tool call

ContentsRequest

Builder for URL content extraction requests.

Constructor

  • new(urls: Vec<String>) -> Self - Create request with URLs (1-10)

Builder Methods

  • with_response_length(length: impl Into<String>) -> Self - Set response length preset
  • with_custom_response_length(chars: i32) -> Self - Set custom character limit (1K-1M)
  • with_extract_effort(effort: impl Into<String>) -> Self - Set extraction effort: "normal", "high", or "auto"
  • with_summary(enabled: bool) -> Self - Enable/disable default summarization
  • with_summary_instructions(instructions: impl Into<String>) -> Self - Set custom summary instructions
  • with_summary_schema(schema: serde_json::Value) -> Self - Set JSON schema for structured extraction
  • with_max_price_dollars(max_price: f64) -> Self - Set maximum price in dollars

AnswerRequest

Builder for AI-powered answer requests.

Constructor

  • new(query: impl Into<String>) -> Self - Create request with query

Builder Methods

  • with_system_instructions(instructions: impl Into<String>) -> Self - Set custom AI instructions (max 2000 chars)
  • with_structured_output(schema: serde_json::Value) -> Self - Set JSON schema for structured response
  • with_search_type(type: impl Into<String>) -> Self - Set search type: "all", "web", or "proprietary"
  • with_fast_mode(enabled: bool) -> Self - Enable fast mode
  • with_data_max_price(price: f64) -> Self - Set maximum data CPM price
  • with_included_sources(sources: Vec<String>) -> Self - Set included sources
  • with_excluded_sources(sources: Vec<String>) -> Self - Set excluded sources
  • with_date_range(start, end) -> Self - Set date range filter
  • with_country_code(code: impl Into<String>) -> Self - Set country code

Response Types

DeepSearchResponse

Fields:

  • success: bool - Whether the request succeeded
  • error: Option<String> - Error message if failed
  • tx_id: Option<String> - Transaction ID
  • query: Option<String> - The search query
  • results: Option<Vec<SearchResult>> - Array of search results
  • results_by_source: Option<ResultsBySource> - Breakdown of results by source
  • total_deduction_dollars: Option<f64> - Cost in dollars
  • total_characters: Option<i32> - Total characters in results

SearchResult

Individual search result with fields including:

  • title: Option<String> - Result title
  • url: Option<String> - Result URL
  • content: Option<String> - Result content/snippet
  • source: Option<String> - Source type
  • publication_date: Option<String> - Publication date
  • authors: Option<Vec<String>> - List of authors
  • citation: Option<String> - Citation information
  • And more...

ContentsResponse

Fields:

  • success: bool - Whether request succeeded
  • results: Option<Vec<ContentResult>> - Extracted content results
  • urls_requested: Option<i32> - Number of URLs requested
  • urls_processed: Option<i32> - Number successfully processed
  • urls_failed: Option<i32> - Number that failed
  • total_cost_dollars: Option<f64> - Total cost

AnswerResponse

Fields:

  • success: bool - Whether request succeeded
  • contents: Option<serde_json::Value> - AI-generated answer (string or structured)
  • data_type: Option<String> - "unstructured" or "structured"
  • search_results: Option<Vec<AnswerSearchResult>> - Sources used
  • search_metadata: Option<AnswerSearchMetadata> - Search metadata
  • ai_usage: Option<AiUsage> - Token usage statistics
  • cost: Option<AnswerCost> - Cost breakdown (search + AI)

Examples

The repository includes several examples demonstrating different use cases:

Basic Search

cargo run --example basic
use valyu::ValyuClient;

let client = ValyuClient::new("your-api-key");
let response = client.search("quantum computing").await?;

println!("Found {} results", response.results.as_ref().map(|r| r.len()).unwrap_or(0));

Academic Research

Search academic papers on specific topics:

use valyu::DeepSearchRequest;

let request = DeepSearchRequest::new("transformer architecture improvements")
    .with_search_type("proprietary")
    .with_included_sources(vec!["valyu/valyu-arxiv".to_string()])
    .with_relevance_threshold(0.7)
    .with_max_results(10);

let response = client.deep_search(&request).await?;

Web Search with Date Filtering

let request = DeepSearchRequest::new("AI safety developments")
    .with_search_type("web")
    .with_date_range("2024-01-01", "2024-12-31")
    .with_max_results(5);

let response = client.deep_search(&request).await?;

Hybrid Search

Search both web and proprietary sources:

let request = DeepSearchRequest::new("quantum computing breakthroughs")
    .with_search_type("all")
    .with_category("technology")
    .with_relevance_threshold(0.6)
    .with_max_price(50.0);

let response = client.deep_search(&request).await?;

Processing Results

let response = client.search("climate change solutions").await?;

if response.success {
    println!("Search cost: ${:.4}", response.total_deduction_dollars.unwrap_or(0.0));

    if let Some(by_source) = &response.results_by_source {
        println!("Sources: Web={:?}, Proprietary={:?}",
            by_source.web, by_source.proprietary);
    }

    if let Some(results) = &response.results {
        for (i, result) in results.iter().enumerate() {
            println!("\n{}. {}", i + 1, result.title.as_deref().unwrap_or("Untitled"));
            println!("   Source: {}", result.source.as_deref().unwrap_or("Unknown"));
            if let Some(content) = &result.content {
                println!("   Content: {}...", &content[..200.min(content.len())]);
            }
        }
    }
}

Content Extraction

cargo run --example contents

Basic content extraction from URLs:

use valyu::ContentsRequest;

let request = ContentsRequest::new(vec![
    "https://example.com/article".to_string(),
]);

let response = client.contents(&request).await?;

if let Some(results) = &response.results {
    for result in results {
        println!("Title: {}", result.title.as_deref().unwrap_or("Untitled"));
        if let Some(content) = &result.content {
            println!("Content: {:?}", content);
        }
    }
}

Content with AI Summary

let request = ContentsRequest::new(vec![
    "https://docs.python.org/3/tutorial/".to_string(),
])
.with_summary(true)
.with_response_length("max");

let response = client.contents(&request).await?;

Structured Data Extraction

use serde_json::json;

let company_schema = json!({
    "type": "object",
    "properties": {
        "company_name": {"type": "string"},
        "founded_year": {"type": "integer"},
        "key_products": {
            "type": "array",
            "items": {"type": "string"},
            "maxItems": 3
        }
    }
});

let request = ContentsRequest::new(vec![
    "https://en.wikipedia.org/wiki/OpenAI".to_string(),
])
.with_summary_schema(company_schema)
.with_response_length("max");

let response = client.contents(&request).await?;

AI-Powered Answers

cargo run --example answer

Get AI-generated answers with sources:

use valyu::AnswerRequest;

let request = AnswerRequest::new("What are the latest developments in quantum computing?")
    .with_search_type("web")
    .with_system_instructions("Focus on breakthroughs from 2024");

let response = client.answer(&request).await?;

if let Some(contents) = &response.contents {
    println!("Answer: {}", contents);
}

if let Some(sources) = &response.search_results {
    println!("\nSources ({}):", sources.len());
    for source in sources {
        println!("  - {}", source.title.as_deref().unwrap_or("Untitled"));
    }
}

Structured Answer Output

cargo run --example answer_structured
use serde_json::json;

let schema = json!({
    "type": "object",
    "properties": {
        "summary": {"type": "string"},
        "key_points": {
            "type": "array",
            "items": {"type": "string"}
        }
    }
});

let request = AnswerRequest::new("quantum computing")
    .with_structured_output(schema);

let response = client.answer(&request).await?;

Multiple URLs Processing

let request = ContentsRequest::new(vec![
    "https://www.valyu.ai/".to_string(),
    "https://docs.valyu.ai/overview".to_string(),
    "https://www.valyu.ai/blogs/why-ai-agents-and-llms-struggle-with-search-and-data-access".to_string(),
])
.with_summary_instructions("Provide key takeaways in bullet points")
.with_max_price_dollars(2.0);

let response = client.contents(&request).await?;

println!("Processed {}/{} URLs",
    response.urls_processed.unwrap_or(0),
    response.urls_requested.unwrap_or(0));
println!("Cost: ${:.4}", response.total_cost_dollars.unwrap_or(0.0));

All Examples

# Basic search example
cargo run --example basic

# Advanced search with custom parameters
cargo run --example advanced

# Content extraction from URLs
cargo run --example contents

# AI-powered answers
cargo run --example answer

# Structured answer output
cargo run --example answer_structured

# Custom HTTP client configuration
cargo run --example custom_client

Note: You'll need to create a .env file with your API key:

cp .env.example .env
# Edit .env and add your VALYU_API_KEY

Known Limitations

As an alpha release, there are some known limitations:

Current Limitations

  • No built-in retry logic: The SDK does not automatically retry requests that fail due to transient errors (503 Service Unavailable, 429 Rate Limit). Implement your own retry logic with exponential backoff if needed.

  • No automatic rate limiting: Rate limit management is left to the user. If you receive 429 errors, implement delays between requests or use a rate limiting library.

  • No streaming support: All responses are returned as complete objects. If the API adds streaming in the future, SDK updates will be required.

  • Limited client-side validation: The SDK performs minimal validation on request parameters (e.g., checking ranges for max_num_results). Invalid parameters will result in API errors.

  • No pagination support: If the API adds pagination for large result sets in the future, SDK updates will be needed.

  • Alpha status: As an alpha release, some APIs and type signatures may change based on user feedback. We will follow semantic versioning for breaking changes.

Workarounds

Implementing Retry Logic

use valyu::{ValyuClient, ValyuError};
use std::time::Duration;
use tokio::time::sleep;

async fn search_with_retry(
    client: &ValyuClient,
    query: &str,
    max_retries: u32,
) -> Result<valyu::DeepSearchResponse, ValyuError> {
    let mut retries = 0;

    loop {
        match client.search(query).await {
            Ok(response) => return Ok(response),
            Err(ValyuError::RateLimitExceeded) | Err(ValyuError::ServiceUnavailable) => {
                if retries >= max_retries {
                    return Err(ValyuError::ServiceUnavailable);
                }
                retries += 1;
                let delay = Duration::from_secs(2_u64.pow(retries));
                sleep(delay).await;
            }
            Err(e) => return Err(e),
        }
    }
}

Rate Limiting

use tokio::time::{sleep, Duration};

// Simple rate limiter: max 10 requests per second
let mut last_request = std::time::Instant::now();
let min_interval = Duration::from_millis(100);

for query in queries {
    let elapsed = last_request.elapsed();
    if elapsed < min_interval {
        sleep(min_interval - elapsed).await;
    }

    let response = client.search(&query).await?;
    last_request = std::time::Instant::now();
}

We welcome feedback on these limitations and suggestions for improvement!

Getting Started

  1. Sign up for a free account at platform.valyu.ai and get $10 free credits
  2. Get your API key from the dashboard
  3. Install the SDK: Add valyu = "0.1" to your Cargo.toml
  4. Start building with the examples above

Documentation

Minimum Supported Rust Version (MSRV)

This crate requires Rust 1.70 or later.

Support

License

Licensed under either of:

at your option.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Before submitting a PR, please make sure to:

  1. Run cargo test to ensure all tests pass
  2. Run cargo fmt to format your code
  3. Run cargo clippy to check for common mistakes
  4. Add tests for any new functionality

Feedback

This SDK is in alpha and we value your feedback! Please open an issue on GitHub to:

  • Report bugs or issues
  • Suggest new features
  • Share your use cases
  • Ask questions

Your input helps us improve the SDK for everyone.

About

Official SDK for the Valyu AI API (alpha)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages