Skip to main content

infinity_provider_protocol/
lib.rs

1//! Extensible model provider abstraction and its remote wire protocol.
2//!
3//! This crate is intentionally lightweight (no HTTP stack, no LLM SDKs) so
4//! that both the agent runtime and out-of-process provider implementations
5//! (e.g. `infinity-provider-bedrock`) can depend on it.
6//!
7//! It defines:
8//!
9//! * The chat [`message`] types and [`completion`] request/stream types that
10//!   form the entire model API surface of this project.
11//! * [`ModelProvider`] — an async trait for listing models and invoking one
12//!   of them, returning a [`ModelStream`] of [`StreamChunk`]s.
13//! * [`remote`] (feature `remote`) — a Unix-socket transport so providers
14//!   can run out of process.
15
16use async_trait::async_trait;
17use serde::{Deserialize, Serialize};
18
19pub mod completion;
20pub mod message;
21#[cfg(feature = "mock")]
22pub mod mock;
23// The remote transport is unix-only for now (Unix domain sockets); the
24// `remote` feature is the stable switch so a Windows transport can slot in
25// behind the same flag later.
26#[cfg(all(unix, feature = "remote"))]
27pub mod remote;
28
29pub use completion::{
30    CompletionError, CompletionRequest, ErrorClass, FinalResponse, ModelStream, StreamChunk,
31    ToolCallDeltaContent, ToolDefinition, Usage,
32};
33pub use message::{
34    AssistantContent, Image, ImageMediaType, ImageSource, Message, Reasoning, ReasoningContent,
35    Text, ToolCall, ToolFunction, ToolResult, ToolResultContent, UserContent,
36};
37
38type BoxError = Box<dyn std::error::Error + Send + Sync>;
39
40/// A model offered by a [`ModelProvider`].
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct ModelEntry {
43    /// Provider-scoped identifier for this model. Must be unique within the
44    /// provider, but need not match the upstream API's model id (providers may
45    /// expose multiple configurations of the same upstream model).
46    pub model_id: String,
47    /// Human-readable name shown in pickers.
48    pub display_name: String,
49    /// Context window size in tokens (used for compaction thresholds).
50    pub context_window: usize,
51    /// Maximum number of output tokens the model can generate per request.
52    /// `None` falls back to the provider's default.
53    pub max_output_tokens: Option<u64>,
54    /// Whether the model accepts image content in its input (e.g. image
55    /// tool results). When `false`, the runtime replaces image content with
56    /// a text placeholder before invoking the model.
57    #[serde(default)]
58    pub supports_image_input: bool,
59}
60
61/// A backend that can list and invoke completion models.
62///
63/// Implementations handle any provider-specific request parameters inside
64/// [`invoke_model`](Self::invoke_model). Providers have no identity of their
65/// own — callers that manage multiple providers (e.g. the daemon) assign each
66/// one a stable unique id at registration time.
67#[async_trait]
68pub trait ModelProvider: Send + Sync {
69    /// List the models available from this provider. The first entry is the
70    /// provider's default model.
71    async fn list_models(&self) -> Result<Vec<ModelEntry>, BoxError>;
72
73    /// Invoke a model by its provider-scoped id, streaming the completion
74    /// response.
75    async fn invoke_model(
76        &self,
77        model_id: &str,
78        request: CompletionRequest,
79    ) -> Result<ModelStream, CompletionError>;
80}
81
82/// A single completion model (as opposed to a provider, which is a catalog
83/// of models). Mostly useful for tests; see [`SingleModelProvider`].
84#[async_trait]
85pub trait CompletionModel: Send + Sync {
86    /// Stream one completion.
87    async fn stream(&self, request: CompletionRequest) -> Result<ModelStream, CompletionError>;
88}
89
90/// Adapter exposing a single [`CompletionModel`] as a [`ModelProvider`].
91/// Useful for tests and simple single-model deployments.
92pub struct SingleModelProvider<M> {
93    entry: ModelEntry,
94    model: M,
95}
96
97impl<M: CompletionModel> SingleModelProvider<M> {
98    pub fn new(entry: ModelEntry, model: M) -> Self {
99        Self { entry, model }
100    }
101}
102
103#[async_trait]
104impl<M: CompletionModel> ModelProvider for SingleModelProvider<M> {
105    async fn list_models(&self) -> Result<Vec<ModelEntry>, BoxError> {
106        Ok(vec![self.entry.clone()])
107    }
108
109    async fn invoke_model(
110        &self,
111        _model_id: &str,
112        request: CompletionRequest,
113    ) -> Result<ModelStream, CompletionError> {
114        self.model.stream(request).await
115    }
116}