Skip to main content

ProviderBackend

Trait ProviderBackend 

Source
pub trait ProviderBackend:
    Send
    + Sync
    + 'static {
    type Model: ModelBackend;

Show 14 methods // Required methods fn model(&self, id: ModelId) -> Result<Self::Model, KitError>; fn shutdown(&self) -> impl Future<Output = Result<(), KitError>> + Send + '_; // Provided methods fn list_models( &self, _request: ModelListRequest, ) -> impl Future<Output = Result<ModelPage, KitError>> + Send + '_ { ... } fn model_info( &self, _id: ModelId, ) -> impl Future<Output = Result<ModelSummary, KitError>> + Send + '_ { ... } fn upload_file( &self, _request: FileUploadRequest, ) -> impl Future<Output = Result<FileObject, KitError>> + Send + '_ { ... } fn list_files( &self, _request: FileListRequest, ) -> impl Future<Output = Result<FilePage, KitError>> + Send + '_ { ... } fn file_info( &self, _id: String, ) -> impl Future<Output = Result<FileObject, KitError>> + Send + '_ { ... } fn delete_file( &self, _id: String, ) -> impl Future<Output = Result<(), KitError>> + Send + '_ { ... } fn download_file( &self, _id: String, _max_bytes: NonZeroUsize, ) -> impl Future<Output = Result<Vec<u8>, KitError>> + Send + '_ { ... } fn batch_status( &self, _id: String, ) -> impl Future<Output = Result<BatchJob, KitError>> + Send + '_ { ... } fn cancel_batch( &self, _id: String, ) -> impl Future<Output = Result<BatchJob, KitError>> + Send + '_ { ... } fn batch_results( &self, _id: String, _max_bytes: NonZeroUsize, ) -> impl Future<Output = Result<Vec<BatchResult<<Self::Model as ModelBackend>::Continuation>>, KitError>> + Send + '_ { ... } fn list_batches( &self, _request: BatchListRequest, ) -> impl Future<Output = Result<BatchPage, KitError>> + Send + '_ { ... } fn health( &self, ) -> impl Future<Output = Result<HealthStatus, KitError>> + Send + '_ { ... }
}
Expand description

Public implementation contract for one provider root.

Provider and Model clones share one lifecycle. Shutdown seals model admission, drains accepted work, and publishes one terminal result to every waiter; cancelling a waiter cannot cancel owned cleanup. Models have no independent shutdown. Caller implementations retain their concrete associated children directly.

§Examples


use providers_kit::{
    ModelBackend, ModelId, Provider, ProviderBackend, ProviderConfig,
    config::{OllamaConfig, ProviderKind, TransportConfig},
};
let provider = Provider::from_config(ProviderConfig::new(
    ProviderKind::Ollama(OllamaConfig::local()),
    TransportConfig::default(),
))?;
let model = provider.model(ModelId::new("exact-model")?)?;
assert_eq!(model.model_id().as_str(), "exact-model");
provider.shutdown().await?;

§Implement a concrete local hierarchy

This runnable caller implementation is a deliberately limited, in-process text echo service, not a language model or proof of any supplied provider. It supports one text message with default settings and text-only Sessions. Optional operations retain their Unsupported defaults. Its work is synchronous and finite: there is no transport, spawned task or asynchronous resource to drain. A real network implementation must additionally own admitted work and shutdown cleanup.

The continuation is caller-owned, cloneable, and deliberately has no serialization contract. Finite streams yield on demand without a forwarding task. Shared closure seals the root and existing children; consuming Session close releases its local queue.

use std::{collections::VecDeque, sync::{Arc, atomic::{AtomicBool, Ordering}}};
use futures_util::{stream, StreamExt};
use providers_kit::{ProviderBackend, ModelBackend, SessionBackend, ModelId, KitError};
use providers_kit::error::{ErrorKind, ErrorPhase, Operation};
use providers_kit::generation::{ContentPart, FinishReason, GenerateEvent,
    GenerateEventStream, GenerateRequest, GenerateResponse, GenerationConfig, Message, Role, Usage};
use providers_kit::session::{SessionConfig, SessionEvent, SessionInput};

#[derive(Clone, Default)]
struct EchoProvider { closed: Arc<AtomicBool> }
#[derive(Clone)]
struct EchoContinuation(Arc<()>);
struct EchoModel { id: ModelId, root: EchoProvider, replay: EchoContinuation }
struct EchoSession { model: ModelId, root: EchoProvider, events: VecDeque<SessionEvent> }

impl EchoProvider {
    fn check(&self, operation: Operation) -> Result<(), KitError> {
        if self.closed.load(Ordering::SeqCst) {
            return Err(KitError::new(ErrorKind::Closed, operation, ErrorPhase::Lifecycle));
        }
        Ok(())
    }
}
impl ProviderBackend for EchoProvider {
    type Model = EchoModel;
    fn model(&self, id: ModelId) -> Result<EchoModel, KitError> {
        self.check(Operation::Generate)?;
        if id.as_str() != "local-echo" {
            return Err(KitError::new(ErrorKind::Unsupported, Operation::Generate,
                ErrorPhase::InputValidation));
        }
        Ok(EchoModel { id, root: self.clone(), replay: EchoContinuation(Arc::new(())) })
    }
    async fn shutdown(&self) -> Result<(), KitError> {
        // No await: sealing and this resource-free cleanup complete together.
        self.closed.store(true, Ordering::SeqCst);
        Ok(())
    }
}
impl EchoModel {
    fn response(&self, request: &GenerateRequest<EchoContinuation>)
        -> Result<GenerateResponse<EchoContinuation>, KitError>
    {
        self.root.check(Operation::Generate)?;
        let unsupported = || KitError::new(ErrorKind::Unsupported,
            Operation::Generate, ErrorPhase::InputValidation);
        if !request.tools().is_empty() || request.reasoning().is_some()
            || request.response_format().is_some()
            || request.generation() != &GenerationConfig::default()
            || request.messages().len() != 1 {
            return Err(unsupported());
        }
        let message = &request.messages()[0];
        if message.role() != Role::User { return Err(unsupported()); }
        let [ContentPart::Text { text }] = message.content() else {
            return Err(unsupported());
        };
        if text.len() > 64 * 1024 { return Err(unsupported()); }
        Ok(GenerateResponse {
            model: self.id.clone(),
            message: Message::assistant_text(text.clone())?
                .with_continuation(self.replay.clone())?,
            finish_reason: Some(FinishReason::Stop),
            citations: Vec::new(), artifacts: Vec::new(), hosted_tool_outputs: Vec::new(),
            usage: Usage::default(), // No token accounting is invented.
        })
    }
}
impl ModelBackend for EchoModel {
    type Continuation = EchoContinuation;
    type Session = EchoSession;
    fn model_id(&self) -> &ModelId { &self.id }
    async fn generate(&self, request: &GenerateRequest<EchoContinuation>)
        -> Result<GenerateResponse<EchoContinuation>, KitError> { self.response(request) }
    async fn generate_stream(&self, request: &GenerateRequest<EchoContinuation>)
        -> Result<GenerateEventStream<EchoContinuation>, KitError>
    {
        let response = self.response(request)?;
        let text: String = response.message.content().iter().filter_map(|part| match part {
            ContentPart::Text { text } => Some(text.as_str()), _ => None,
        }).collect();
        Ok(GenerateEventStream::new(stream::iter([
            Ok(GenerateEvent::Started { model: self.id.clone() }),
            Ok(GenerateEvent::ContentDelta { delta: text }),
            Ok(GenerateEvent::Completed(Box::new(response))),
        ])))
    }
    async fn open_session(&self, config: SessionConfig) -> Result<EchoSession, KitError> {
        self.root.check(Operation::OpenSession)?;
        if config != SessionConfig::default() {
            return Err(KitError::new(ErrorKind::Unsupported, Operation::OpenSession,
                ErrorPhase::InputValidation));
        }
        Ok(EchoSession { model: self.id.clone(), root: self.root.clone(), events: VecDeque::new() })
    }
}
impl SessionBackend for EchoSession {
    fn id(&self) -> &str { "local-echo-session" }
    fn model_id(&self) -> &ModelId { &self.model }
    async fn send(&mut self, input: SessionInput) -> Result<(), KitError> {
        self.root.check(Operation::SessionSend)?;
        if !self.events.is_empty() {
            return Err(KitError::new(ErrorKind::InvalidState, Operation::SessionSend,
                ErrorPhase::Lifecycle));
        }
        match input {
            SessionInput::Text { text } if !text.trim().is_empty() && text.len() <= 64 * 1024 => {
                self.events.push_back(SessionEvent::TextDelta { delta: text });
                self.events.push_back(SessionEvent::Completed);
                Ok(())
            }
            _ => Err(KitError::new(ErrorKind::Unsupported, Operation::SessionSend,
                ErrorPhase::InputValidation)),
        }
    }
    async fn recv(&mut self) -> Result<SessionEvent, KitError> {
        self.root.check(Operation::SessionReceive)?;
        self.events.pop_front().ok_or_else(|| KitError::new(ErrorKind::InvalidState,
            Operation::SessionReceive, ErrorPhase::Lifecycle))
    }
    async fn close(self) -> Result<(), KitError> { Ok(()) }
}

let provider = EchoProvider::default();
let model = provider.model(ModelId::new("local-echo")?)?;
let request = GenerateRequest::new(vec![Message::user_text("hello")?])?;
let response = model.generate(&request).await?;
assert!(matches!(response.message.content(), [ContentPart::Text { text }] if text == "hello"));
assert!(Arc::ptr_eq(&response.message.continuation().unwrap().0, &model.replay.0));
let mut events = model.generate_stream(&request).await?;
assert!(matches!(events.next().await.transpose()?, Some(GenerateEvent::Started { .. })));
assert!(
    matches!(events.next().await.transpose()?, Some(GenerateEvent::ContentDelta { delta }) if delta == "hello")
);
assert!(matches!(events.next().await.transpose()?, Some(GenerateEvent::Completed(_))));
assert!(events.next().await.is_none());
let mut session = model.open_session(SessionConfig::default()).await?;
session.send(SessionInput::Text { text: "hello again".into() }).await?;
assert!(
    matches!(session.recv().await?, SessionEvent::TextDelta { delta } if delta == "hello again")
);
assert_eq!(session.recv().await?, SessionEvent::Completed);
session.close().await?;
provider.shutdown().await?;
assert_eq!(model.generate(&request).await.err().unwrap().kind(), ErrorKind::Closed);
provider.shutdown().await?; // Replays the same resource-free terminal result.

Required Associated Types§

Source

type Model: ModelBackend

Exact model child returned by this provider.

Required Methods§

Source

fn model(&self, id: ModelId) -> Result<Self::Model, KitError>

Selects one exact provider-local model.

§Errors

Returns an error when root admission is closed or the selected implementation cannot construct this exact model. Selection never silently falls back to another model.

See crate::ProviderBackend for a complete example.

Source

fn shutdown(&self) -> impl Future<Output = Result<(), KitError>> + Send + '_

Shuts down backend-owned resources.

Retain cleanup independently of each borrowed waiter. Repeated and concurrent calls replay the same terminal result; last-handle drop is not an async cleanup API.

§Errors

Returns the shared backend cleanup failure, if any. A cancelled waiter does not reset shutdown or abandon cleanup.

§Examples

use providers_kit::{
    ModelBackend, ModelId, Provider, ProviderBackend, ProviderConfig,
    config::{OllamaConfig, ProviderKind, TransportConfig},
};
let provider = Provider::from_config(ProviderConfig::new(
    ProviderKind::Ollama(OllamaConfig::local()),
    TransportConfig::default(),
))?;
let clone = provider.clone();
provider.shutdown().await?;
clone.shutdown().await?;
assert!(clone.model(ModelId::new("exact-model")?).is_err());

Provided Methods§

Source

fn list_models( &self, _request: ModelListRequest, ) -> impl Future<Output = Result<ModelPage, KitError>> + Send + '_

Lists provider-visible models.

This example requires a real configured service, valid credentials, and any exact resource ids shown. The default trait implementation returns Unsupported.

§Errors

Returns KitError classified as Unsupported when unavailable, Closed after sealing, or the owning input, transport, deadline, service-rejection, or response-validation category. Inspect kind() and context() rather than diagnostic prose.

§Examples

use providers_kit::{
    Provider, ProviderBackend, ProviderConfig,
    config::{ApiKey, OpenAiConfig, ProviderKind, TransportConfig},
};
let provider = Provider::from_config(ProviderConfig::new(
    ProviderKind::OpenAi(OpenAiConfig::new(ApiKey::new("replace-with-your-key")?)),
    TransportConfig::default(),
))?;
let result = provider.list_models(providers_kit::models::ModelListRequest::default()).await;
let cleanup = provider.shutdown().await;
if let Err(error) = &cleanup {
    eprintln!("Cleanup failed: {error}");
}
let page = result?;
cleanup?;
for model in page.models {
    println!("{}", model.id.as_str());
}
Source

fn model_info( &self, _id: ModelId, ) -> impl Future<Output = Result<ModelSummary, KitError>> + Send + '_

Fetches descriptive metadata for one exact provider-local model.

This example requires a real configured service, valid credentials, and any exact resource ids shown. The default trait implementation returns Unsupported.

§Errors

Returns KitError classified as Unsupported when unavailable, Closed after sealing, or the owning input, transport, deadline, service-rejection, or response-validation category. Inspect kind() and context() rather than diagnostic prose.

§Examples

use providers_kit::{
    Provider, ProviderBackend, ProviderConfig,
    config::{ApiKey, OpenAiConfig, ProviderKind, TransportConfig},
};
let provider = Provider::from_config(ProviderConfig::new(
    ProviderKind::OpenAi(OpenAiConfig::new(ApiKey::new("replace-with-your-key")?)),
    TransportConfig::default(),
))?;
let result = provider.model_info(providers_kit::ModelId::new("your-exact-model-id")?).await;
let cleanup = provider.shutdown().await;
if let Err(error) = &cleanup {
    eprintln!("Cleanup failed: {error}");
}
let _value = result?;
cleanup?;
Source

fn upload_file( &self, _request: FileUploadRequest, ) -> impl Future<Output = Result<FileObject, KitError>> + Send + '_

Uploads one provider-managed file.

This example requires a real configured service, valid credentials, and any exact resource ids shown. Only delete or cancel resources the caller owns. The default trait implementation returns Unsupported.

§Errors

Returns KitError classified as Unsupported when unavailable, Closed after sealing, or the owning input, transport, deadline, service-rejection, or response-validation category. Inspect kind() and context() rather than diagnostic prose.

§Examples

use providers_kit::{
    Provider, ProviderBackend, ProviderConfig,
    config::{ApiKey, OpenAiConfig, ProviderKind, TransportConfig},
};
let provider = Provider::from_config(ProviderConfig::new(
    ProviderKind::OpenAi(OpenAiConfig::new(ApiKey::new("replace-with-your-key")?)),
    TransportConfig::default(),
))?;
let result = provider
    .upload_file(providers_kit::files::FileUploadRequest::new(
        "notes.txt",
        "text/plain",
        b"notes".to_vec(),
    )?)
    .await;
let deletion = match &result {
    Ok(file) => provider.delete_file(file.id.clone()).await,
    Err(_) => Ok(()),
};
let cleanup = provider.shutdown().await;
if let Err(error) = &cleanup {
    eprintln!("Cleanup failed: {error}");
}
let _value = result?;
deletion?;
cleanup?;
Source

fn list_files( &self, _request: FileListRequest, ) -> impl Future<Output = Result<FilePage, KitError>> + Send + '_

Lists provider-managed files.

This example requires a real configured service, valid credentials, and any exact resource ids shown. Only delete or cancel resources the caller owns. The default trait implementation returns Unsupported.

§Errors

Returns KitError classified as Unsupported when unavailable, Closed after sealing, or the owning input, transport, deadline, service-rejection, or response-validation category. Inspect kind() and context() rather than diagnostic prose.

§Examples

use providers_kit::{
    Provider, ProviderBackend, ProviderConfig,
    config::{ApiKey, OpenAiConfig, ProviderKind, TransportConfig},
};
let provider = Provider::from_config(ProviderConfig::new(
    ProviderKind::OpenAi(OpenAiConfig::new(ApiKey::new("replace-with-your-key")?)),
    TransportConfig::default(),
))?;
let result = provider.list_files(providers_kit::files::FileListRequest::default()).await;
let cleanup = provider.shutdown().await;
if let Err(error) = &cleanup {
    eprintln!("Cleanup failed: {error}");
}
let _value = result?;
cleanup?;
Source

fn file_info( &self, _id: String, ) -> impl Future<Output = Result<FileObject, KitError>> + Send + '_

Fetches metadata for one provider-managed file.

This example requires a real configured service, valid credentials, and any exact resource ids shown. Only delete or cancel resources the caller owns. The default trait implementation returns Unsupported.

§Errors

Returns KitError classified as Unsupported when unavailable, Closed after sealing, or the owning input, transport, deadline, service-rejection, or response-validation category. Inspect kind() and context() rather than diagnostic prose.

§Examples

use providers_kit::{
    Provider, ProviderBackend, ProviderConfig,
    config::{ApiKey, OpenAiConfig, ProviderKind, TransportConfig},
};
let provider = Provider::from_config(ProviderConfig::new(
    ProviderKind::OpenAi(OpenAiConfig::new(ApiKey::new("replace-with-your-key")?)),
    TransportConfig::default(),
))?;
let result = provider.file_info("owned-file-id".into()).await;
let cleanup = provider.shutdown().await;
if let Err(error) = &cleanup {
    eprintln!("Cleanup failed: {error}");
}
let _value = result?;
cleanup?;
Source

fn delete_file( &self, _id: String, ) -> impl Future<Output = Result<(), KitError>> + Send + '_

Deletes one provider-managed file.

This example requires a real configured service, valid credentials, and any exact resource ids shown. Only delete or cancel resources the caller owns. The default trait implementation returns Unsupported.

§Errors

Returns KitError classified as Unsupported when unavailable, Closed after sealing, or the owning input, transport, deadline, service-rejection, or response-validation category. Inspect kind() and context() rather than diagnostic prose.

§Examples

use providers_kit::{
    Provider, ProviderBackend, ProviderConfig,
    config::{ApiKey, OpenAiConfig, ProviderKind, TransportConfig},
};
let provider = Provider::from_config(ProviderConfig::new(
    ProviderKind::OpenAi(OpenAiConfig::new(ApiKey::new("replace-with-your-key")?)),
    TransportConfig::default(),
))?;
let result = provider.delete_file("owned-file-id".into()).await;
let cleanup = provider.shutdown().await;
if let Err(error) = &cleanup {
    eprintln!("Cleanup failed: {error}");
}
let _value = result?;
cleanup?;
Source

fn download_file( &self, _id: String, _max_bytes: NonZeroUsize, ) -> impl Future<Output = Result<Vec<u8>, KitError>> + Send + '_

Downloads one provider-managed file under the caller’s byte limit.

This example requires a real configured service, valid credentials, and any exact resource ids shown. Only delete or cancel resources the caller owns. The default trait implementation returns Unsupported.

§Errors

Returns KitError classified as Unsupported when unavailable, Closed after sealing, or the owning input, transport, deadline, service-rejection, or response-validation category. Inspect kind() and context() rather than diagnostic prose.

§Examples

use providers_kit::{
    Provider, ProviderBackend, ProviderConfig,
    config::{ApiKey, OpenAiConfig, ProviderKind, TransportConfig},
};
let provider = Provider::from_config(ProviderConfig::new(
    ProviderKind::OpenAi(OpenAiConfig::new(ApiKey::new("replace-with-your-key")?)),
    TransportConfig::default(),
))?;
let result = provider
    .download_file(
        "owned-file-id".into(),
        std::num::NonZeroUsize::new(1024 * 1024).unwrap(),
    )
    .await;
let cleanup = provider.shutdown().await;
if let Err(error) = &cleanup {
    eprintln!("Cleanup failed: {error}");
}
let _value = result?;
cleanup?;
Source

fn batch_status( &self, _id: String, ) -> impl Future<Output = Result<BatchJob, KitError>> + Send + '_

Fetches one batch job.

Supplied OpenAI status reads opt into the configured bounded transport retries; every attempt shares the original absolute request deadline. This does not retry decoding or successful-response body failures. The lookup used by batch_results is excluded. See the batch workflow.

This example requires a real configured service, valid credentials, and any exact resource ids shown. Only delete or cancel resources the caller owns. The default trait implementation returns Unsupported.

§Errors

Returns KitError classified as Unsupported when unavailable, Closed after sealing, or the owning input, transport, deadline, service-rejection, or response-validation category. Inspect kind() and context() rather than diagnostic prose.

§Examples

use providers_kit::{
    Provider, ProviderBackend, ProviderConfig,
    config::{ApiKey, OpenAiConfig, ProviderKind, TransportConfig},
};
let provider = Provider::from_config(ProviderConfig::new(
    ProviderKind::OpenAi(OpenAiConfig::new(ApiKey::new("replace-with-your-key")?)),
    TransportConfig::default(),
))?;
let result = provider.batch_status("owned-batch-id".into()).await;
let cleanup = provider.shutdown().await;
if let Err(error) = &cleanup {
    eprintln!("Cleanup failed: {error}");
}
let _value = result?;
cleanup?;
Source

fn cancel_batch( &self, _id: String, ) -> impl Future<Output = Result<BatchJob, KitError>> + Send + '_

Requests cancellation of one batch job.

Acknowledgement is not terminality: the returned job may still be running. Observe its status until terminal before cleaning up owned input files; see the bounded batch workflow.

This example requires a real configured service, valid credentials, and any exact resource ids shown. Only delete or cancel resources the caller owns. The default trait implementation returns Unsupported.

§Errors

Returns KitError classified as Unsupported when unavailable, Closed after sealing, or the owning input, transport, deadline, service-rejection, or response-validation category. Inspect kind() and context() rather than diagnostic prose.

§Examples

use providers_kit::{
    Provider, ProviderBackend, ProviderConfig,
    config::{ApiKey, OpenAiConfig, ProviderKind, TransportConfig},
};
let provider = Provider::from_config(ProviderConfig::new(
    ProviderKind::OpenAi(OpenAiConfig::new(ApiKey::new("replace-with-your-key")?)),
    TransportConfig::default(),
))?;
let result = provider.cancel_batch("owned-batch-id".into()).await;
let cleanup = provider.shutdown().await;
if let Err(error) = &cleanup {
    eprintln!("Cleanup failed: {error}");
}
let _value = result?;
cleanup?;
Source

fn batch_results( &self, _id: String, _max_bytes: NonZeroUsize, ) -> impl Future<Output = Result<Vec<BatchResult<<Self::Model as ModelBackend>::Continuation>>, KitError>> + Send + '_

Downloads and normalizes batch result rows under the caller’s byte limit.

This example requires a real configured service, valid credentials, and any exact resource ids shown. Only delete or cancel resources the caller owns. The default trait implementation returns Unsupported. The byte bound covers the downloaded result; each terminal row must be inspected independently. Row failures are result data, while download/normalization failures are outer errors.

§Errors

Returns KitError classified as Unsupported when unavailable, Closed after sealing, or the owning input, transport, deadline, service-rejection, or response-validation category. Inspect kind() and context() rather than diagnostic prose.

§Examples

use providers_kit::{
    Provider, ProviderBackend, ProviderConfig,
    config::{ApiKey, OpenAiConfig, ProviderKind, TransportConfig},
};
let provider = Provider::from_config(ProviderConfig::new(
    ProviderKind::OpenAi(OpenAiConfig::new(ApiKey::new("replace-with-your-key")?)),
    TransportConfig::default(),
))?;
let result = provider
    .batch_results(
        "owned-batch-id".into(),
        std::num::NonZeroUsize::new(1024 * 1024).unwrap(),
    )
    .await;
let cleanup = provider.shutdown().await;
if let Err(error) = &cleanup {
    eprintln!("Cleanup failed: {error}");
}
let _value = result?;
cleanup?;
Source

fn list_batches( &self, _request: BatchListRequest, ) -> impl Future<Output = Result<BatchPage, KitError>> + Send + '_

Lists provider batch jobs.

This example requires a real configured service, valid credentials, and any exact resource ids shown. Only delete or cancel resources the caller owns. The default trait implementation returns Unsupported.

§Errors

Returns KitError classified as Unsupported when unavailable, Closed after sealing, or the owning input, transport, deadline, service-rejection, or response-validation category. Inspect kind() and context() rather than diagnostic prose.

§Examples

use providers_kit::{
    Provider, ProviderBackend, ProviderConfig,
    config::{ApiKey, OpenAiConfig, ProviderKind, TransportConfig},
};
let provider = Provider::from_config(ProviderConfig::new(
    ProviderKind::OpenAi(OpenAiConfig::new(ApiKey::new("replace-with-your-key")?)),
    TransportConfig::default(),
))?;
let result = provider.list_batches(providers_kit::batch::BatchListRequest::default()).await;
let cleanup = provider.shutdown().await;
if let Err(error) = &cleanup {
    eprintln!("Cleanup failed: {error}");
}
let _value = result?;
cleanup?;
Source

fn health( &self, ) -> impl Future<Output = Result<HealthStatus, KitError>> + Send + '_

Probes provider runtime health.

This example requires a real configured service, valid credentials, and any exact resource ids shown. The default trait implementation returns Unsupported.

§Errors

Returns KitError classified as Unsupported when unavailable, Closed after sealing, or the owning input, transport, deadline, service-rejection, or response-validation category. Inspect kind() and context() rather than diagnostic prose.

§Examples

use providers_kit::{
    Provider, ProviderBackend, ProviderConfig,
    config::{ApiKey, OpenAiConfig, ProviderKind, TransportConfig},
};
let provider = Provider::from_config(ProviderConfig::new(
    ProviderKind::OpenAi(OpenAiConfig::new(ApiKey::new("replace-with-your-key")?)),
    TransportConfig::default(),
))?;
let result = provider.health().await;
let cleanup = provider.shutdown().await;
if let Err(error) = &cleanup {
    eprintln!("Cleanup failed: {error}");
}
let _value = result?;
cleanup?;

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§