tarzi 0.2.3

Rust-native lite search for AI applications
Documentation
API Search Examples
===================

This guide demonstrates tarzi's search access cascade: API → plain HTTP → headless browser.

Access Cascade
--------------

With ``search.browser = true`` (default), tarzi tries:

1. **API** when the engine supports it and credentials are present (env probed first)
2. **Plain HTTP** to the engine's public search URL
3. **Browser** as a last resort (disable with ``TARZI_SEARCH_BROWSER=false``)

Use a comma-separated ``TARZI_SEARCH_ENGINE`` list for ordered engine failover.
API-only engines without credentials are skipped before any network call.

Engine Capabilities
-------------------

.. list-table::
   :header-rows: 1
   :widths: 22 15 15 48

   * - Engine
     - Web
     - API
     - Notes
   * - ``bing``
     - Yes
     - No
     - In default failover list
   * - ``google``
     - Yes
     - No
     - HTML only; use ``google_serper`` for API
   * - ``google_serper`` / ``serper``
     - No
     - Yes
     - Requires ``SERPER_API_KEY``
   * - ``brave``
     - Yes
     - Yes
     - ``BRAVE_API_KEY`` for API path; in default failover
   * - ``duckduckgo``
     - Yes
     - No
     - First in default failover; plain HTML URL differs from browser SERP
   * - ``baidu`` / ``sogou_weixin``
     - Yes
     - No
     - Web cascade only

Supported API Engines
---------------------

- **Brave** (``brave``): Brave Search API via ``BRAVE_API_KEY`` or ``search.api_key``
- **Google Serper** (``google_serper`` / ``serper``): Serper API via ``SERPER_API_KEY`` or ``search.api_key``

``google`` remains web-only. There is no Google Custom Search (CSE) integration.

Basic API Search
----------------

Python
~~~~~~

.. code-block:: python

   import tarzi

   config_str = """
   [search]
   engine = "brave"
   browser = true
   limit = 5
   api_key = "your-brave-api-key"
   """

   config = tarzi.Config.from_str(config_str)
   search_engine = tarzi.SearchEngine.from_config(config)

   try:
       results = search_engine.search("artificial intelligence trends", 5)
       print(f"Found {len(results)} results:")
       for i, result in enumerate(results):
           print(f"{i+1}. {result.title}")
           print(f"   URL: {result.url}")
           print(f"   Snippet: {result.snippet[:150]}...")
   except Exception as e:
       print(f"Search failed: {e}")

Rust
~~~~

.. code-block:: rust

   use tarzi::{config::Config, search::SearchEngine};

   #[tokio::main]
   async fn main() -> Result<(), Box<dyn std::error::Error>> {
       let mut config = Config::new();
       config.search.engine = "brave".to_string();
       config.search.browser = false;
       config.search.limit = 5;
       config.search.api_key = Some("your-brave-api-key".to_string());

       let mut search_engine = SearchEngine::from_config(&config);

       match search_engine.search("machine learning applications", 5).await {
           Ok(results) => {
               println!("Found {} results:", results.len());
               for (i, result) in results.iter().enumerate() {
                   println!("{}. {}", i + 1, result.title);
                   println!("   URL: {}", result.url);
               }
           }
           Err(e) => println!("Search failed: {}", e),
       }

       Ok(())
   }

Google via Serper
-----------------

.. code-block:: toml

   [search]
   engine = "google_serper"
   browser = false
   limit = 10
   # Prefer env: export SERPER_API_KEY=...
   # api_key = "your-serper-api-key"

Skipping API (web engines)
--------------------------

Use a web-capable engine and leave API keys unset so the cascade starts at plain HTTP.
Set ``browser = false`` to skip WebDriver as well:

.. code-block:: python

   import tarzi

   config = tarzi.Config.from_str(
       """
   [search]
   engine = "duckduckgo,bing"
   browser = false
   limit = 5
   """
   )
   engine = tarzi.SearchEngine.from_config(config)
   results = engine.search("rust async", 5)

Environment Variables
---------------------

- ``BRAVE_API_KEY`` — Brave Search API
- ``SERPER_API_KEY`` — Google Serper API

Environment variables take precedence over ``search.api_key`` in config.

Runnable Examples
-----------------

From the repository ``examples/`` directory:

.. code-block:: bash

   cargo run --example search_cascade
   cargo run --example search_engine_brave
   cargo run --example search_engine_serper

   python examples/search_cascade.py
   python examples/search_engine_serper.py

See also :doc:`/configuration` for the full engine capability table.