Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Model providers

An Agent uses a provider for completion calls. Providers can connect to a real model or supply deterministic answers for offline tests.

Provider contract

Implement Provider::complete to translate a ProviderRequest into one model call and return a ProviderResponse. Forward the system instructions, input, schema and output limit. Report actual input/output token counts when available; leave unknown values as None. Providers own retries and rate limits and should report usage for the whole call.

The model-extraction example runs a complete crawl with MockSite and spire::testing::Script, without a network or API key:

cargo run -p model-extraction

Enable agent and testing to use Script in your own tests. It can return a queue of ProviderResponses, answer from a synchronous or asynchronous callback, and capture requests for assertions.

For Rig models, enable agent-rig on the facade:

[dependencies]
spire = { version = "0.9.0", features = ["agent-rig", "reqwest"] }

The upstream crate is re-exported as spire::agent::rig.

Wrap a Rig completion model with spire::agent::Rig::new(model), then pass it to Agent::new. The adapter includes the schema in the prompt by default. Opt into with_native_schema() when the model supports native structured output. Answers are validated in both modes. Rig’s reported input/output token usage is preserved.

Offline tests

Enable agent and testing on the facade to use the built-in Script provider. Fixed responses are useful for handler tests:

use spire::testing::Script;
use spire::agent::{Agent, ProviderResponse, Usage};

#[tokio::main(flavor = "current_thread")]
async fn main() -> spire::agent::Result<()> {
    let provider = Script::new([ProviderResponse {
        text: r#"{"result":["Basic"]}"#.into(),
        usage: Usage::tokens(10, 5),
    }]);
    let agent = Agent::new(provider.clone());
    let names: Vec<String> = agent.extract("Basic").await?;
    assert_eq!(names, ["Basic"]);
    assert_eq!(provider.calls(), 1);
    Ok(())
}

Script::from_fn answers synchronously from each request; Script::from_async_fn supports controlled latency and cancellation. requests() captures calls in arrival order, including failures, while calls() counts them. Clones share the queue and request log. An exhausted response queue fails instead of silently repeating the last answer.

Use it with MockSite to exercise the whole crawl without a network or model API key. Account for budgets and caches when asserting the number of provider calls.