diff --git a/src/adapter/adapter_types.rs b/src/adapter/adapter_types.rs index b8d27ae..b8534ad 100644 --- a/src/adapter/adapter_types.rs +++ b/src/adapter/adapter_types.rs @@ -1,8 +1,8 @@ -use crate::adapter::Result; use crate::adapter::{AdapterConfig, AdapterKind}; use crate::chat::{ChatRequest, ChatRequestOptionsSet, ChatResponse, ChatStreamResponse}; use crate::webc::WebResponse; use crate::ConfigSet; +use crate::Result; use reqwest::RequestBuilder; use serde_json::Value; diff --git a/src/adapter/adapters/anthropic/adapter_impl.rs b/src/adapter/adapters/anthropic/adapter_impl.rs index 0d6357d..23ed696 100644 --- a/src/adapter/adapters/anthropic/adapter_impl.rs +++ b/src/adapter/adapters/anthropic/adapter_impl.rs @@ -1,6 +1,6 @@ use crate::adapter::anthropic::AnthropicStreamer; use crate::adapter::support::get_api_key_resolver; -use crate::adapter::Result; +use crate::Result; use crate::adapter::{Adapter, AdapterConfig, AdapterKind, ServiceType, WebRequestData}; use crate::chat::{ ChatRequest, ChatRequestOptionsSet, ChatResponse, ChatRole, ChatStream, ChatStreamResponse, MessageContent, diff --git a/src/adapter/adapters/anthropic/streamer.rs b/src/adapter/adapters/anthropic/streamer.rs index 8b23d60..82e79d1 100644 --- a/src/adapter/adapters/anthropic/streamer.rs +++ b/src/adapter/adapters/anthropic/streamer.rs @@ -1,6 +1,6 @@ use crate::adapter::adapters::support::{StreamerCapturedData, StreamerOptions}; use crate::adapter::inter_stream::{InterStreamEnd, InterStreamEvent}; -use crate::adapter::{Error, Result}; +use crate::{Error, Result}; use crate::chat::{ChatRequestOptionsSet, MetaUsage}; use crate::support::value_ext::ValueExt; use reqwest_eventsource::{Event, EventSource}; diff --git a/src/adapter/adapters/cohere/adapter_impl.rs b/src/adapter/adapters/cohere/adapter_impl.rs index cd171b2..64db489 100644 --- a/src/adapter/adapters/cohere/adapter_impl.rs +++ b/src/adapter/adapters/cohere/adapter_impl.rs @@ -1,7 +1,6 @@ use crate::adapter::cohere::CohereStreamer; use crate::adapter::support::get_api_key_resolver; use crate::adapter::{Adapter, AdapterConfig, AdapterKind, ServiceType, WebRequestData}; -use crate::adapter::{Error, Result}; use crate::chat::{ ChatRequest, ChatRequestOptionsSet, ChatResponse, ChatRole, ChatStream, ChatStreamResponse, MessageContent, MetaUsage, @@ -9,6 +8,7 @@ use crate::chat::{ use crate::support::value_ext::ValueExt; use crate::webc::{WebResponse, WebStream}; use crate::ConfigSet; +use crate::{Error, Result}; use reqwest::RequestBuilder; use serde_json::{json, Value}; use std::sync::OnceLock; @@ -96,15 +96,17 @@ impl Adapter for CohereAdapter { Ok(WebRequestData { url, headers, payload }) } - fn to_chat_response(_kind: AdapterKind, web_response: WebResponse) -> Result { + fn to_chat_response(adapter_kind: AdapterKind, web_response: WebResponse) -> Result { let WebResponse { mut body, .. } = web_response; // -- Get usage let usage = body.x_take("/meta/tokens").map(Self::into_usage).unwrap_or_default(); // -- Get response - let mut last_chat_history_item = - body.x_take::>("chat_history")?.pop().ok_or(Error::NoChatResponse)?; + let mut last_chat_history_item = body + .x_take::>("chat_history")? + .pop() + .ok_or(Error::NoChatResponse { adapter_kind })?; let content: Option = last_chat_history_item .x_take::>("message")? @@ -173,7 +175,7 @@ impl CohereAdapter { } // -- Build extract the last user message - let last_chat_msg = chat_req.messages.pop().ok_or(Error::ChatReqHasNoMessages)?; + let last_chat_msg = chat_req.messages.pop().ok_or(Error::ChatReqHasNoMessages { adapter_kind })?; if !matches!(last_chat_msg.role, ChatRole::User) { return Err(Error::LastChatMessageIsNoUser { actual_role: last_chat_msg.role, @@ -193,7 +195,7 @@ impl CohereAdapter { ChatRole::User => chat_history.push(json! ({"role": "USER", "content": content})), ChatRole::Assistant => chat_history.push(json! ({"role": "CHATBOT", "content": content})), ChatRole::Tool => { - return Err(Error::MessageRoleNotSupport { + return Err(Error::MessageRoleNotSupported { adapter_kind, role: ChatRole::Tool, }) diff --git a/src/adapter/adapters/cohere/streamer.rs b/src/adapter/adapters/cohere/streamer.rs index d9f4d6d..302ecf2 100644 --- a/src/adapter/adapters/cohere/streamer.rs +++ b/src/adapter/adapters/cohere/streamer.rs @@ -1,10 +1,11 @@ use crate::adapter::adapters::support::{StreamerCapturedData, StreamerOptions}; use crate::adapter::cohere::CohereAdapter; use crate::adapter::inter_stream::{InterStreamEnd, InterStreamEvent}; -use crate::adapter::{Error, Result}; +use crate::adapter::AdapterKind; use crate::chat::ChatRequestOptionsSet; use crate::support::value_ext::ValueExt; use crate::webc::WebStream; +use crate::{Error, Result}; use serde::Deserialize; use serde_json::Value; use std::pin::Pin; @@ -118,7 +119,10 @@ impl futures::Stream for CohereStreamer { } Some(Err(err)) => { println!("Cohere Adapter Stream Error: {}", err); - return Poll::Ready(Some(Err(Error::WebStream))); + return Poll::Ready(Some(Err(Error::WebStream { + adapter_kind: AdapterKind::Cohere, + cause: err.to_string(), + }))); } None => { self.done = true; diff --git a/src/adapter/adapters/gemini/adapter_impl.rs b/src/adapter/adapters/gemini/adapter_impl.rs index f086a71..066e9fb 100644 --- a/src/adapter/adapters/gemini/adapter_impl.rs +++ b/src/adapter/adapters/gemini/adapter_impl.rs @@ -1,7 +1,6 @@ use crate::adapter::gemini::GeminiStreamer; use crate::adapter::support::get_api_key_resolver; use crate::adapter::{Adapter, AdapterConfig, AdapterKind, ServiceType, WebRequestData}; -use crate::adapter::{Error, Result}; use crate::chat::{ ChatRequest, ChatRequestOptionsSet, ChatResponse, ChatRole, ChatStream, ChatStreamResponse, MessageContent, MetaUsage, @@ -9,6 +8,7 @@ use crate::chat::{ use crate::support::value_ext::ValueExt; use crate::webc::{WebResponse, WebStream}; use crate::ConfigSet; +use crate::{Error, Result}; use reqwest::RequestBuilder; use serde_json::{json, Value}; use std::sync::OnceLock; @@ -177,7 +177,7 @@ impl GeminiAdapter { ChatRole::User => contents.push(json! ({"role": "user", "parts": [{"text": content}]})), ChatRole::Assistant => contents.push(json! ({"role": "model", "parts": [{"text": content}]})), ChatRole::Tool => { - return Err(Error::MessageRoleNotSupport { + return Err(Error::MessageRoleNotSupported { adapter_kind, role: ChatRole::Tool, }) diff --git a/src/adapter/adapters/gemini/streamer.rs b/src/adapter/adapters/gemini/streamer.rs index 19a6e3d..9a7efab 100644 --- a/src/adapter/adapters/gemini/streamer.rs +++ b/src/adapter/adapters/gemini/streamer.rs @@ -1,9 +1,10 @@ use crate::adapter::adapters::support::{StreamerCapturedData, StreamerOptions}; use crate::adapter::gemini::{GeminiAdapter, GeminiChatResponse}; use crate::adapter::inter_stream::{InterStreamEnd, InterStreamEvent}; -use crate::adapter::{Error, Result}; +use crate::adapter::AdapterKind; use crate::chat::ChatRequestOptionsSet; use crate::webc::WebStream; +use crate::{Error, Result}; use serde_json::Value; use std::pin::Pin; use std::task::{Context, Poll}; @@ -106,7 +107,10 @@ impl futures::Stream for GeminiStreamer { } Some(Err(err)) => { println!("Gemini Adapter Stream Error: {}", err); - return Poll::Ready(Some(Err(Error::WebStream))); + return Poll::Ready(Some(Err(Error::WebStream { + adapter_kind: AdapterKind::Gemini, + cause: err.to_string(), + }))); } None => { self.done = true; diff --git a/src/adapter/adapters/groq/adapter_impl.rs b/src/adapter/adapters/groq/adapter_impl.rs index b3d0ce7..c6b6684 100644 --- a/src/adapter/adapters/groq/adapter_impl.rs +++ b/src/adapter/adapters/groq/adapter_impl.rs @@ -1,6 +1,6 @@ use crate::adapter::openai::OpenAIAdapter; use crate::adapter::support::get_api_key_resolver; -use crate::adapter::Result; +use crate::Result; use crate::adapter::{Adapter, AdapterConfig, AdapterKind, ServiceType, WebRequestData}; use crate::chat::{ChatRequest, ChatRequestOptionsSet, ChatResponse, ChatStreamResponse}; use crate::webc::WebResponse; diff --git a/src/adapter/adapters/ollama/adapter_impl.rs b/src/adapter/adapters/ollama/adapter_impl.rs index e75cd7b..c7784a9 100644 --- a/src/adapter/adapters/ollama/adapter_impl.rs +++ b/src/adapter/adapters/ollama/adapter_impl.rs @@ -1,12 +1,12 @@ //! API DOC: https://github.com/ollama/ollama/blob/main/docs/openai.md use crate::adapter::openai::OpenAIAdapter; -use crate::adapter::Result; use crate::adapter::{Adapter, AdapterConfig, AdapterKind, ServiceType, WebRequestData}; use crate::chat::{ChatRequest, ChatRequestOptionsSet, ChatResponse, ChatStreamResponse}; use crate::support::value_ext::ValueExt; use crate::webc::WebResponse; use crate::ConfigSet; +use crate::{Error, Result}; use reqwest::RequestBuilder; use serde_json::Value; use std::sync::OnceLock; @@ -22,12 +22,15 @@ const OLLAMA_BASE_URL: &str = "http://localhost:11434/api/"; /// Since the base ollama API supports `application/x-ndjson` for streaming whereas others support `text/event-stream` impl Adapter for OllamaAdapter { /// Note: For now returns empty as it should probably do a request to the ollama server - async fn all_model_names(_kind: AdapterKind) -> Result> { + async fn all_model_names(adapter_kind: AdapterKind) -> Result> { let url = format!("{OLLAMA_BASE_URL}tags"); // TODO: need to get the WebClient from the client. let web_c = crate::webc::WebClient::default(); - let mut res = web_c.do_get(&url, &[]).await?; + let mut res = web_c.do_get(&url, &[]).await.map_err(|webc_error| Error::WebCall { + adapter_kind, + webc_error, + })?; let mut models: Vec = Vec::new(); diff --git a/src/adapter/adapters/openai/adapter_impl.rs b/src/adapter/adapters/openai/adapter_impl.rs index 1b6b450..ee0eb4a 100644 --- a/src/adapter/adapters/openai/adapter_impl.rs +++ b/src/adapter/adapters/openai/adapter_impl.rs @@ -1,7 +1,6 @@ use crate::adapter::openai::OpenAIStreamer; use crate::adapter::support::get_api_key_resolver; use crate::adapter::{Adapter, AdapterConfig, AdapterKind, ServiceType, WebRequestData}; -use crate::adapter::{Error, Result}; use crate::chat::{ ChatRequest, ChatRequestOptionsSet, ChatResponse, ChatRole, ChatStream, ChatStreamResponse, MessageContent, MetaUsage, @@ -9,6 +8,7 @@ use crate::chat::{ use crate::support::value_ext::ValueExt; use crate::webc::WebResponse; use crate::ConfigSet; +use crate::{Error, Result}; use reqwest::RequestBuilder; use reqwest_eventsource::EventSource; use serde_json::{json, Value}; @@ -194,7 +194,7 @@ impl OpenAIAdapter { ChatRole::User => messages.push(json! ({"role": "user", "content": content})), ChatRole::Assistant => messages.push(json! ({"role": "assistant", "content": content})), ChatRole::Tool => { - return Err(Error::MessageRoleNotSupport { + return Err(Error::MessageRoleNotSupported { adapter_kind, role: ChatRole::Tool, }) diff --git a/src/adapter/adapters/openai/streamer.rs b/src/adapter/adapters/openai/streamer.rs index 6da95f9..547ed7c 100644 --- a/src/adapter/adapters/openai/streamer.rs +++ b/src/adapter/adapters/openai/streamer.rs @@ -2,9 +2,9 @@ use crate::adapter::adapters::support::{StreamerCapturedData, StreamerOptions}; use crate::adapter::inter_stream::{InterStreamEnd, InterStreamEvent}; use crate::adapter::openai::OpenAIAdapter; use crate::adapter::AdapterKind; -use crate::adapter::{Error, Result}; use crate::chat::ChatRequestOptionsSet; use crate::support::value_ext::ValueExt; +use crate::{Error, Result}; use reqwest_eventsource::{Event, EventSource}; use serde_json::Value; use std::pin::Pin; diff --git a/src/adapter/dispatcher.rs b/src/adapter/dispatcher.rs index b8e108c..13aa739 100644 --- a/src/adapter/dispatcher.rs +++ b/src/adapter/dispatcher.rs @@ -3,11 +3,11 @@ use crate::adapter::cohere::CohereAdapter; use crate::adapter::gemini::GeminiAdapter; use crate::adapter::ollama::OllamaAdapter; use crate::adapter::openai::OpenAIAdapter; -use crate::adapter::Result; use crate::adapter::{Adapter, AdapterConfig, AdapterKind, ServiceType, WebRequestData}; use crate::chat::{ChatRequest, ChatRequestOptionsSet, ChatResponse, ChatStreamResponse}; use crate::webc::WebResponse; use crate::ConfigSet; +use crate::Result; use reqwest::RequestBuilder; use super::groq::GroqAdapter; diff --git a/src/adapter/error.rs b/src/adapter/error.rs deleted file mode 100644 index a44c7eb..0000000 --- a/src/adapter/error.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::adapter::AdapterKind; -use crate::chat::ChatRole; -use crate::{resolver, webc}; -use derive_more::From; - -pub type Result = core::result::Result; - -#[derive(Debug, From)] -pub enum Error { - // -- Adapter Chat Request - ChatReqHasNoMessages, - LastChatMessageIsNoUser { - actual_role: ChatRole, - }, - - // -- Adapter Chat Response - NoChatResponse, - - // -- Adapter - RequiresApiKey { - adapter_kind: AdapterKind, - }, - MessageRoleNotSupport { - adapter_kind: AdapterKind, - role: ChatRole, - }, - HasNoDefaultApiKeyEnvName, - NoAuthResolver { - adapter_kind: AdapterKind, - }, - AuthResolverNoAuthData { - adapter_kind: AdapterKind, - }, - - // -- Stream - StreamParse(serde_json::Error), - StreamEventError(serde_json::Value), - WebStream, - - // -- Modules - #[from] - Webc(webc::Error), - #[from] - Resolver(resolver::Error), - - // -- Utils - #[from] - XValue(crate::support::value_ext::Error), - - // -- Externals - #[from] - EventSourceClone(reqwest_eventsource::CannotCloneRequestError), - ReqwestEventSource(reqwest_eventsource::Error), -} - -// region: --- Error Boilerplate - -impl core::fmt::Display for Error { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> { - write!(fmt, "{self:?}") - } -} - -impl std::error::Error for Error {} - -// endregion: --- Error Boilerplate diff --git a/src/adapter/mod.rs b/src/adapter/mod.rs index 05d35fe..4004a1e 100644 --- a/src/adapter/mod.rs +++ b/src/adapter/mod.rs @@ -14,7 +14,6 @@ mod adapter_kind; mod adapter_types; mod adapters; mod dispatcher; -mod error; mod support; // -- Flatten (private, crate, public) @@ -23,7 +22,6 @@ use adapters::*; pub(crate) use adapter_types::*; pub(crate) use dispatcher::*; -pub use self::error::{Error, Result}; pub use adapter_config::*; pub use adapter_kind::*; diff --git a/src/adapter/support.rs b/src/adapter/support.rs index 0840114..3d5bf44 100644 --- a/src/adapter/support.rs +++ b/src/adapter/support.rs @@ -1,6 +1,6 @@ use crate::adapter::AdapterKind; -use crate::adapter::{Error, Result}; use crate::ConfigSet; +use crate::{Error, Result}; /// Returns the `api_key` value from the config_set auth_resolver /// This function should be called if the adapter must have a api_key diff --git a/src/chat/chat_stream.rs b/src/chat/chat_stream.rs index d1ccde4..499cce4 100644 --- a/src/chat/chat_stream.rs +++ b/src/chat/chat_stream.rs @@ -5,7 +5,7 @@ use futures::Stream; use std::pin::Pin; use std::task::{Context, Poll}; -type InterStreamType = Pin>>>; +type InterStreamType = Pin>>>; pub struct ChatStream { inter_stream: InterStreamType, @@ -18,7 +18,7 @@ impl ChatStream { pub fn from_inter_stream(inter_stream: T) -> Self where - T: Stream> + Unpin + 'static, + T: Stream> + Unpin + 'static, { let boxed_stream: InterStreamType = Box::pin(inter_stream); ChatStream::new(boxed_stream) @@ -28,7 +28,7 @@ impl ChatStream { // region: --- Stream Impl impl Stream for ChatStream { - type Item = crate::adapter::Result; + type Item = crate::Result; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let this = self.get_mut(); diff --git a/src/client/client_impl.rs b/src/client/client_impl.rs index 6a26982..e6518df 100644 --- a/src/client/client_impl.rs +++ b/src/client/client_impl.rs @@ -1,7 +1,7 @@ use crate::adapter::{Adapter, AdapterDispatcher, AdapterKind, ServiceType, WebRequestData}; use crate::chat::{ChatRequest, ChatRequestOptions, ChatRequestOptionsSet, ChatResponse, ChatStreamResponse}; use crate::client::Client; -use crate::{ConfigSet, Result}; +use crate::{ConfigSet, Error, Result}; /// Public AI Functions impl Client { @@ -66,7 +66,14 @@ impl Client { options_set, )?; - let web_res = self.web_client().do_post(&url, &headers, payload).await?; + let web_res = + self.web_client() + .do_post(&url, &headers, payload) + .await + .map_err(|webc_error| Error::WebCall { + adapter_kind, + webc_error, + })?; let chat_res = AdapterDispatcher::to_chat_response(adapter_kind, web_res)?; @@ -100,7 +107,13 @@ impl Client { options_set.clone(), )?; - let reqwest_builder = self.web_client().new_req_builder(&url, &headers, payload)?; + let reqwest_builder = self + .web_client() + .new_req_builder(&url, &headers, payload) + .map_err(|webc_error| Error::WebCall { + adapter_kind, + webc_error, + })?; let res = AdapterDispatcher::to_chat_stream(adapter_kind, reqwest_builder, options_set)?; diff --git a/src/error.rs b/src/error.rs index c6cda04..367c19e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,16 +1,68 @@ -use crate::adapter::{self}; -use crate::webc; +use crate::adapter::AdapterKind; +use crate::chat::ChatRole; +use crate::{resolver, webc}; use derive_more::From; pub type Result = core::result::Result; #[derive(Debug, From)] pub enum Error { - #[from] - Webc(webc::Error), + // -- Chat Input + ChatReqHasNoMessages { + adapter_kind: AdapterKind, + }, + LastChatMessageIsNoUser { + actual_role: ChatRole, + }, + MessageRoleNotSupported { + adapter_kind: AdapterKind, + role: ChatRole, + }, + // -- Chat Output + NoChatResponse { + adapter_kind: AdapterKind, + }, + + // -- Auth + RequiresApiKey { + adapter_kind: AdapterKind, + }, + NoAuthResolver { + adapter_kind: AdapterKind, + }, + AuthResolverNoAuthData { + adapter_kind: AdapterKind, + }, + + // -- Web Call error + WebCall { + adapter_kind: AdapterKind, + webc_error: webc::Error, + }, + + // -- Chat Stream + StreamParse(serde_json::Error), + StreamEventError(serde_json::Value), + WebStream { + adapter_kind: AdapterKind, + cause: String, + }, + + // -- Modules + // #[from] + // Webc(webc::Error), #[from] - Adapter(adapter::Error), + Resolver(resolver::Error), + + // -- Utils + #[from] + XValue(crate::support::value_ext::Error), + + // -- Externals + #[from] + EventSourceClone(reqwest_eventsource::CannotCloneRequestError), + ReqwestEventSource(reqwest_eventsource::Error), } // region: --- Error Boilerplate diff --git a/src/resolver/mod.rs b/src/resolver/mod.rs index 2535d88..d837e9f 100644 --- a/src/resolver/mod.rs +++ b/src/resolver/mod.rs @@ -9,8 +9,8 @@ mod adapter_kind_resolver; mod auth_resolver; mod error; -pub use self::error::{Error, Result}; pub use adapter_kind_resolver::*; pub use auth_resolver::*; +pub use error::{Error, Result}; // endregion: --- Modules diff --git a/src/webc/mod.rs b/src/webc/mod.rs index 98820d0..935aa03 100644 --- a/src/webc/mod.rs +++ b/src/webc/mod.rs @@ -5,7 +5,7 @@ mod web_client; // for when not `text/event-stream` mod web_stream; -pub use self::error::{Error, Result}; +pub use error::{Error, Result}; pub use web_client::*; pub use web_stream::*;