Skip to main content

looprs_core/ports/
inference_provider.rs

1//! InferenceProvider port — abstraction over LLM inference backends.
2
3use serde::{Deserialize, Serialize};
4
5use crate::api::{ContentBlock, Message, ToolDefinition};
6use crate::types::ModelId;
7
8/// Request structure for LLM inference.
9#[derive(Debug, Clone)]
10pub struct InferenceRequest {
11    pub model: ModelId,
12    pub messages: Vec<Message>,
13    pub tools: Vec<ToolDefinition>,
14    pub max_tokens: u32,
15    pub temperature: Option<f32>,
16    pub system: String,
17}
18
19/// Response structure from LLM inference.
20#[derive(Debug, Clone)]
21pub struct InferenceResponse {
22    pub content: Vec<ContentBlock>,
23    pub stop_reason: String,
24    pub usage: Usage,
25}
26
27/// Token usage information.
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct Usage {
30    pub input_tokens: u32,
31    pub output_tokens: u32,
32}
33
34/// Port: perform LLM inference.
35///
36/// Implementations decide the backend (Anthropic, OpenAI, local Ollama, etc.).
37#[async_trait::async_trait]
38// TODO: add provider conformance test suite — a shared test matrix exercising
39// every InferenceProvider implementation: correct tool-use round-trip, retry on
40// 429, model name normalisation, timeout propagation. Wire via
41// assert_inference_provider_contract() in test_contracts.rs. Live tests already
42// opt-in via LOOPRS_RUN_LIVE_LLM_TESTS=1.
43pub trait InferenceProvider: Send + Sync {
44    /// Run inference with the given request.
45    async fn infer(
46        &self,
47        req: &InferenceRequest,
48    ) -> Result<InferenceResponse, Box<dyn std::error::Error + Send + Sync>>;
49
50    /// Get the name of this provider.
51    fn name(&self) -> &str;
52
53    /// Get the model being used.
54    fn model(&self) -> &ModelId;
55
56    /// Validate that this provider is properly configured.
57    fn validate_config(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
58
59    /// Whether this provider supports tool use (function calling).
60    fn supports_tool_use(&self) -> bool {
61        true
62    }
63}