klieo_llm_common/lib.rs
1#![deny(missing_docs)]
2#![deny(rust_2018_idioms)]
3#![deny(rustdoc::broken_intra_doc_links)]
4
5//! Provider-agnostic plumbing shared by every `klieo-llm-*` provider
6//! crate.
7//!
8//! The Anthropic, OpenAI, Gemini, and Ollama clients all duplicated the
9//! same HTTP-client builder and the same `reqwest::Error` →
10//! [`LlmError`] mapping. A tuning change had to land in four files;
11//! security defaults (TLS redirect policy, connect timeout) could
12//! silently drift between providers.
13//!
14//! This crate centralises:
15//!
16//! - [`build_http_client`] + [`HttpDefaults`] — single factory with
17//! redirects disabled (CWE-200: bearer-token leak via cross-origin
18//! redirect).
19//! - [`map_reqwest`] — `reqwest::Error` → [`LlmError`] dispatch.
20//! - [`retry_after_from_headers`] — RFC 7231 `Retry-After` parser.
21//! Provider crates previously hardcoded `retry_after_secs = 1`; this
22//! lets them honour the upstream's actual hint.
23//!
24//! SSE-event decoding is NOT shared: the frame splitter itself is five
25//! lines per crate, and the per-provider event dispatch loop sitting on
26//! top is genuinely different (Anthropic typed events, OpenAI choices
27//! deltas, Gemini candidates, Ollama JSON-per-line). Sharing the
28//! splitter alone would add an abstraction without removing the bulk.
29//!
30//! [`LlmError`]: klieo_core::error::LlmError
31
32pub mod error;
33pub mod http;
34
35pub use crate::error::{
36 map_reqwest, map_status_code, retry_after_from_headers, truncate_error_detail,
37 StatusMessageKind,
38};
39pub use crate::http::{build_http_client, HttpDefaults, DEFAULT_HTTP_DEFAULTS};