Skip to main content

FakeProvider

Struct FakeProvider 

Source
pub struct FakeProvider { /* private fields */ }
Expand description

A stand-in for a real provider, for use in tests.

Register it into a Registry under a normal provider name (e.g. "openai") and it behaves like the real thing as far as your application code can tell – except instead of making a network call, it hands back canned responses you scripted ahead of time with respond_with, and records every request it received so you can assert on what your code actually sent.

§Example

use llmprism::testing::{FakeProvider, FakeTextResponse};
use llmprism::Registry;

let fake = FakeProvider::new("openai").respond_with(FakeTextResponse::new("Hello!"));

let mut registry = Registry::new();
registry.register("openai", fake);

// Code under test just calls `registry.text("openai", ...)` as normal, with
// no idea it's talking to a fake.
let response = registry.text("openai", "gpt-4o-mini").unwrap()
    .with_prompt("hi")
    .generate()
    .await
    .unwrap();

assert_eq!(response.text.as_deref(), Some("Hello!"));

The same scripted responses work for stream too – FakeProvider synthesizes StreamEvents from the canned Step instead of needing a second, stream-shaped fixture format. By default it yields one word per StreamEvent::TextDelta; change that with with_stream_chunk_words.

Every capability keeps its own independent queue (text, structured output, moderation, and so on) – a test exercising more than one capability against the same fake scripts each separately, e.g. respond_with_structured alongside respond_with.

Implementations§

Source§

impl FakeProvider

Source

pub fn new(name: impl Into<String>) -> Self

Creates a fake provider that will report name from Provider::name, with no canned responses queued yet.

Source

pub fn respond_with(self, step: impl Into<Step>) -> Self

Queues one canned response, to be returned the next time this provider is called. Call this once per request/response round trip you expect your test to trigger – for example, twice if you’re testing a single tool call followed by a final reply.

Source

pub fn respond_with_structured( self, response: impl Into<StructuredResponse>, ) -> Self

Queues one canned structured-output response, to be returned the next time this provider receives a structured request. Kept as a separate queue from respond_with since a structured response is a different shape (StructuredResponse, not Step) – a test that exercises both capabilities scripts each independently.

Source

pub fn respond_with_moderation( self, response: impl Into<ModerationResponse>, ) -> Self

Queues one canned moderation response, to be returned the next time this provider receives a moderation request.

Source

pub fn respond_with_embeddings( self, response: impl Into<EmbeddingsResponse>, ) -> Self

Queues one canned embeddings response, to be returned the next time this provider receives an embeddings request.

Source

pub fn respond_with_rerank(self, response: impl Into<RerankResponse>) -> Self

Queues one canned rerank response, to be returned the next time this provider receives a rerank request.

Source

pub fn respond_with_images(self, response: impl Into<ImagesResponse>) -> Self

Queues one canned image-generation response, to be returned the next time this provider receives an images request.

Source

pub fn respond_with_audio(self, response: impl Into<AudioResponse>) -> Self

Queues one canned text-to-speech response, to be returned the next time this provider receives a text-to-speech request.

Source

pub fn respond_with_transcription( self, response: impl Into<TranscriptionResponse>, ) -> Self

Queues one canned speech-to-text response, to be returned the next time this provider receives a speech-to-text request.

Source

pub fn with_stream_chunk_words(self, words: usize) -> Self

Controls how many words stream_text_once groups into each StreamEvent::TextDelta it synthesizes from a canned response’s text. Defaults to one word per delta; raise it if a test wants fewer, larger chunks.

Source

pub fn recorded_requests(&self) -> Vec<TextRequest>

Returns every request this provider actually received, in order – useful for asserting on exactly what your code sent (which model, which messages, which tools, and so on).

Source

pub fn recorded_structured_requests(&self) -> Vec<StructuredRequest>

Returns every structured request this provider actually received, in order – the structured-output counterpart to recorded_requests.

Source

pub fn recorded_moderation_requests(&self) -> Vec<ModerationRequest>

Returns every moderation request this provider actually received, in order.

Source

pub fn recorded_embeddings_requests(&self) -> Vec<EmbeddingsRequest>

Returns every embeddings request this provider actually received, in order.

Source

pub fn recorded_rerank_requests(&self) -> Vec<RerankRequest>

Returns every rerank request this provider actually received, in order.

Source

pub fn recorded_images_requests(&self) -> Vec<ImagesRequest>

Returns every images request this provider actually received, in order.

Source

pub fn recorded_text_to_speech_requests(&self) -> Vec<TextToSpeechRequest>

Returns every text-to-speech request this provider actually received, in order.

Source

pub fn recorded_speech_to_text_requests(&self) -> Vec<SpeechToTextRequest>

Returns every speech-to-text request this provider actually received, in order.

Trait Implementations§

Source§

impl Provider for FakeProvider

Source§

fn name(&self) -> &str

A short, lowercase identifier for this provider, used in error messages (and, when registered normally, as the key applications pass to Registry::text).
Source§

fn text_step<'life0, 'life1, 'async_trait>( &'life0 self, request: &'life1 TextRequest, ) -> Pin<Box<dyn Future<Output = Result<Step, Error>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Performs exactly one request/response round trip against the provider’s text-generation endpoint – send the current conversation, get back one reply. Read more
Source§

fn stream_text_once<'life0, 'life1, 'async_trait>( &'life0 self, request: &'life1 TextRequest, ) -> Pin<Box<dyn Future<Output = Result<BoxStream<'static, Result<StreamEvent, Error>>, Error>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

The streaming counterpart to text_step: performs exactly one request/response round trip, but instead of waiting for the whole reply, returns a stream that yields StreamEvents as they arrive. Read more
Source§

fn structured<'life0, 'async_trait>( &'life0 self, request: StructuredRequest, ) -> Pin<Box<dyn Future<Output = Result<StructuredResponse, Error>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Performs a structured-output request: send a conversation plus a schema, get back one reply guaranteed to match that schema’s shape. Read more
Source§

fn stream_structured_once<'life0, 'life1, 'async_trait>( &'life0 self, request: &'life1 StructuredRequest, ) -> Pin<Box<dyn Future<Output = Result<BoxStream<'static, Result<StructuredStreamEvent, Error>>, Error>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

The streaming counterpart to structured: instead of waiting for the whole reply, returns a stream that yields StructuredStreamEvent::PartialObjects as the model’s JSON output arrives, ending with exactly one StructuredStreamEvent::End. Like structured, this is always exactly one round trip – there’s no separate loop layer above it. Read more
Source§

fn moderation<'life0, 'async_trait>( &'life0 self, request: ModerationRequest, ) -> Pin<Box<dyn Future<Output = Result<ModerationResponse, Error>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Checks one or more pieces of text against the provider’s content-safety classifier. Not every provider has a moderation endpoint – Anthropic, notably, doesn’t – so this defaults to Error::Unsupported like every other optional capability here.
Source§

fn embeddings<'life0, 'async_trait>( &'life0 self, request: EmbeddingsRequest, ) -> Pin<Box<dyn Future<Output = Result<EmbeddingsResponse, Error>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Turns one or more pieces of text into embedding vectors.
Source§

fn rerank<'life0, 'async_trait>( &'life0 self, request: RerankRequest, ) -> Pin<Box<dyn Future<Output = Result<RerankResponse, Error>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Scores and sorts a list of documents by relevance to a query. See crate::rerank for how this differs from embeddings.
Source§

fn images<'life0, 'async_trait>( &'life0 self, request: ImagesRequest, ) -> Pin<Box<dyn Future<Output = Result<ImagesResponse, Error>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Generates one or more images from a text prompt.
Source§

fn text_to_speech<'life0, 'async_trait>( &'life0 self, request: TextToSpeechRequest, ) -> Pin<Box<dyn Future<Output = Result<AudioResponse, Error>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Turns text into spoken audio.
Source§

fn speech_to_text<'life0, 'async_trait>( &'life0 self, request: SpeechToTextRequest, ) -> Pin<Box<dyn Future<Output = Result<TranscriptionResponse, Error>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Transcribes spoken audio into text.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more