just_llm_client/lib.rs
1//! Provider-neutral LLM client abstractions built on top of the provider type crates in this
2//! workspace.
3//!
4//! # Architecture
5//!
6//! Two building blocks on top of the provider type crates:
7//!
8//! - **Backend adapters** ([`crate::provider::DeepSeekBackend`], [`crate::provider::OpenAiCompatBackend`]):
9//! fully-constructed LLM adapters that hold a `reqwest::Client` and base URL directly, expose
10//! always-on operations, and negotiate optional capabilities such as model catalogs or balance
11//! inspection. Every backend implements [`LlmBackend`], which also carries the uniform
12//! [`new`](LlmBackend::new) constructor and [`family`](LlmBackend::family) identifier used for
13//! construction and error attribution.
14//!
15//! - **[`BackendFactory`]**: a composable `family -> constructor` dispatch table. It maps a
16//! backend family string (see the [`family`] module) to that backend's
17//! [`LlmBackend::new`], building a fresh shared backend on each
18//! [`create`](BackendFactory::create). It holds no configuration and caches nothing — downstream
19//! composes any registry or sharing policy on top.
20//!
21//! [`ChatClient`] pairs per-call defaults (model, system prompt) with a shared [`LlmBackend`] and
22//! derefs to `dyn LlmBackend`, so chat and capability methods are reachable directly. Construct a
23//! backend via [`BackendFactory`] or [`LlmBackend::new`], then wrap it in a [`ChatClient`].
24//!
25//! # Prepare-send-parse pattern
26//!
27//! [`LlmBackend`] exposes a prepare-send-parse pattern that gives callers full access to the HTTP
28//! response, including headers like `retry-after` and `x-ratelimit-*`, before deserializing:
29//!
30//! ```ignore
31//! let prepared = backend.prepare(request)?; // reqwest::Request (Send + Sync; try_clone-able)
32//! let response = backend.send(prepared).await?; // raw reqwest::Response, status unchecked
33//! // Inspect status / headers (retry-after, x-ratelimit-*) here, or re-send a clone of `prepared` (via try_clone) for retry.
34//! let retry_after = response.headers().get("retry-after");
35//! let completion = backend.parse(response).await?; // deserialized via dyn dispatch
36//! ```
37//!
38//! # Capability traits
39//!
40//! Every backend adapter implements [`LlmBackend`], which provides the prepare/send/parse
41//! primitives (with streaming variants) and the `chat_completion`/`stream_chat_completion`
42//! convenience methods, all with concrete types (no associated types). [`ChatClient`]
43//! derefs to `dyn LlmBackend` so all methods are available without importing the trait explicitly.
44//! Optional operations are negotiated through [`CapabilityNegotiation`] before use so
45//! [`CapabilityError::Unsupported`] is reported at the negotiation boundary instead of from the
46//! capability method itself.
47//!
48//! # DTO layering
49//!
50//! Some request and response types across provider type crates and this crate are intentionally
51//! similar. That repetition is a trade-off so provider crates can evolve as independent
52//! wire-level units — merging the code would not automatically make that boundary easier
53//! to maintain.
54//!
55//! The shared types in this crate aim to be conservative abstractions. When a provider
56//! cannot supply a piece of data faithfully, the normalized type should represent that
57//! absence explicitly instead of fabricating certainty.
58#![warn(missing_docs)]
59
60/// Capability traits exposed by the LLM client layer.
61pub mod capability;
62/// Unified chat client and backend factory.
63pub mod client;
64/// LLM client error taxonomy.
65pub mod error;
66/// Built-in backend family identifiers.
67pub mod family;
68/// Provider adapters and runtime provider selection.
69pub mod provider;
70/// Local tool runtime helpers.
71pub mod tools;
72/// Shared normalized value types.
73pub mod types;
74
75pub use capability::{
76 Balance, CapabilityNegotiation, ChatCompletionStream, Identifiable, ModelCatalog,
77};
78pub use error::{BackendConstructError, BackendError, Capability, CapabilityError};
79pub use just_common::error::{ProviderError, TransportError};
80pub use just_common::transport::http::{build_client, endpoint_url, ensure_success, parse_json};
81pub use just_common::transport::sse::JsonEventStream;
82pub use provider::LlmBackend;
83pub use provider::validation::{
84 into_validated_streaming_request, validate_common_request, validate_non_streaming_request,
85};
86pub use tools::{LlmTool, ToolCallError, ToolDispatcher, ToolRegistrationError};
87
88pub use client::{BackendFactory, ChatClient, ChatClientOptions};