diff --git a/crates/owlen-core/src/lib.rs b/crates/owlen-core/src/lib.rs index 2b0fb6b..831a8e4 100644 --- a/crates/owlen-core/src/lib.rs +++ b/crates/owlen-core/src/lib.rs @@ -18,6 +18,7 @@ pub mod mcp; pub mod mode; pub mod model; pub mod oauth; +pub mod provider; pub mod providers; pub mod router; pub mod sandbox; @@ -50,6 +51,7 @@ pub use mcp::{ }; pub use mode::*; pub use model::*; +pub use provider::*; pub use providers::*; pub use router::*; pub use sandbox::*; diff --git a/crates/owlen-core/src/provider/mod.rs b/crates/owlen-core/src/provider/mod.rs new file mode 100644 index 0000000..7424a5b --- /dev/null +++ b/crates/owlen-core/src/provider/mod.rs @@ -0,0 +1,34 @@ +//! Unified provider abstraction layer. +//! +//! This module defines the async [`ModelProvider`] trait that all model +//! backends implement, together with a small suite of shared data structures +//! used for model discovery and streaming generation. + +mod types; + +use std::pin::Pin; + +use async_trait::async_trait; +use futures::Stream; + +pub use self::types::*; + +use crate::Result; + +/// Convenience alias for the stream type yielded by [`ModelProvider::generate_stream`]. +pub type GenerateStream = Pin> + Send + 'static>>; + +#[async_trait] +pub trait ModelProvider: Send + Sync { + /// Returns descriptive metadata about the provider. + fn metadata(&self) -> &ProviderMetadata; + + /// Check the current health state for the provider. + async fn health_check(&self) -> Result; + + /// List all models available through the provider. + async fn list_models(&self) -> Result>; + + /// Acquire a streaming response for a generation request. + async fn generate_stream(&self, request: GenerateRequest) -> Result; +} diff --git a/crates/owlen-core/src/provider/types.rs b/crates/owlen-core/src/provider/types.rs new file mode 100644 index 0000000..a6f64ac --- /dev/null +++ b/crates/owlen-core/src/provider/types.rs @@ -0,0 +1,124 @@ +//! Shared types used by the unified provider abstraction layer. + +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +/// Categorises providers so the UI can distinguish between local and hosted +/// backends. +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +pub enum ProviderType { + Local, + Cloud, +} + +/// Represents the current availability state for a provider. +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +pub enum ProviderStatus { + Available, + Unavailable, + RequiresSetup, +} + +/// Describes core metadata for a provider implementation. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct ProviderMetadata { + pub id: String, + pub name: String, + pub provider_type: ProviderType, + pub requires_auth: bool, + #[serde(default)] + pub metadata: HashMap, +} + +impl ProviderMetadata { + /// Construct a new metadata instance for a provider. + pub fn new( + id: impl Into, + name: impl Into, + provider_type: ProviderType, + requires_auth: bool, + ) -> Self { + Self { + id: id.into(), + name: name.into(), + provider_type, + requires_auth, + metadata: HashMap::new(), + } + } +} + +/// Information about a model that can be displayed to users. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct ModelInfo { + pub name: String, + #[serde(default)] + pub size_bytes: Option, + #[serde(default)] + pub capabilities: Vec, + #[serde(default)] + pub description: Option, + pub provider: ProviderMetadata, + #[serde(default)] + pub metadata: HashMap, +} + +/// Unified request for streaming text generation across providers. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct GenerateRequest { + pub model: String, + #[serde(default)] + pub prompt: Option, + #[serde(default)] + pub context: Vec, + #[serde(default)] + pub parameters: HashMap, + #[serde(default)] + pub metadata: HashMap, +} + +impl GenerateRequest { + /// Helper for building a request from the minimum required fields. + pub fn new(model: impl Into) -> Self { + Self { + model: model.into(), + prompt: None, + context: Vec::new(), + parameters: HashMap::new(), + metadata: HashMap::new(), + } + } +} + +/// Streamed chunk of generation output from a model. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct GenerateChunk { + #[serde(default)] + pub text: Option, + #[serde(default)] + pub is_final: bool, + #[serde(default)] + pub metadata: HashMap, +} + +impl GenerateChunk { + /// Construct a new chunk with the provided text payload. + pub fn from_text(text: impl Into) -> Self { + Self { + text: Some(text.into()), + is_final: false, + metadata: HashMap::new(), + } + } + + /// Mark the chunk as the terminal item in a stream. + pub fn final_chunk() -> Self { + Self { + text: None, + is_final: true, + metadata: HashMap::new(), + } + } +}