converge_core/traits/
llm.rs1use super::error::{CapabilityError, ErrorCategory};
11pub use converge_provider::chat::{
12 BoxFuture, ChatBackend, ChatMessage, ChatRequest, ChatResponse, ChatRole, DynChatBackend,
13 FinishReason, LlmError, ResponseFormat, TokenUsage, ToolCall, ToolDefinition,
14};
15use std::future::Future;
16use std::time::Duration;
17
18#[derive(Debug, Clone)]
20pub struct EmbedRequest {
21 pub inputs: Vec<String>,
22 pub model: Option<String>,
23 pub dimensions: Option<u32>,
24}
25
26#[derive(Debug, Clone)]
28pub struct EmbedResponse {
29 pub embeddings: Vec<Vec<f32>>,
30 pub usage: Option<TokenUsage>,
31 pub model: Option<String>,
32}
33
34impl CapabilityError for LlmError {
35 fn category(&self) -> ErrorCategory {
36 match self {
37 Self::RateLimited { .. } => ErrorCategory::RateLimit,
38 Self::Timeout { .. } => ErrorCategory::Timeout,
39 Self::AuthDenied { .. } => ErrorCategory::Auth,
40 Self::InvalidRequest { .. } => ErrorCategory::InvalidInput,
41 Self::ModelNotFound { .. } => ErrorCategory::NotFound,
42 Self::ContextLengthExceeded { .. } => ErrorCategory::InvalidInput,
43 Self::ContentFiltered { .. } => ErrorCategory::InvalidInput,
44 Self::ResponseFormatMismatch { .. } => ErrorCategory::Internal,
45 Self::ProviderError { .. } => ErrorCategory::Internal,
46 Self::NetworkError { .. } => ErrorCategory::Unavailable,
47 }
48 }
49
50 fn is_transient(&self) -> bool {
51 matches!(
52 self,
53 Self::RateLimited { .. } | Self::Timeout { .. } | Self::NetworkError { .. }
54 )
55 }
56
57 fn is_retryable(&self) -> bool {
58 self.is_transient() || matches!(self, Self::ProviderError { .. })
59 }
60
61 fn retry_after(&self) -> Option<Duration> {
62 match self {
63 Self::RateLimited { retry_after, .. } => Some(*retry_after),
64 _ => None,
65 }
66 }
67}
68
69pub trait EmbedBackend: Send + Sync {
71 type EmbedFut<'a>: Future<Output = Result<EmbedResponse, LlmError>> + Send + 'a
72 where
73 Self: 'a;
74
75 fn embed<'a>(&'a self, req: EmbedRequest) -> Self::EmbedFut<'a>;
76}
77
78pub trait LlmBackend: ChatBackend + EmbedBackend {}
80
81impl<T: ChatBackend + EmbedBackend> LlmBackend for T {}
82
83pub trait DynEmbedBackend: Send + Sync {
85 fn embed(&self, req: EmbedRequest) -> BoxFuture<'_, Result<EmbedResponse, LlmError>>;
86}
87
88impl<T: EmbedBackend> DynEmbedBackend for T {
89 fn embed(&self, req: EmbedRequest) -> BoxFuture<'_, Result<EmbedResponse, LlmError>> {
90 Box::pin(EmbedBackend::embed(self, req))
91 }
92}