turnframe_provider/lib.rs
1//! `turnframe-provider`: the provider-neutral model layer of Turnframe (spec §20).
2//!
3//! The core runtime never sees OpenAI-, Anthropic-, Gemini- or Bedrock-specific
4//! wire types (spec §0 rule 8). It speaks this crate's normalized vocabulary:
5//!
6//! * a [`request::ModelRequest`] describes one model call: purpose, messages,
7//! expected [`request::OutputSpec`], read-only tools, limits and metadata;
8//! * a [`response::ModelResponse`] carries the normalized answer, a
9//! [`response::FinishReason`] and [`response::TokenUsage`];
10//! * a [`stream::ModelStream`] delivers the same answer incrementally and
11//! [`stream::reconstruct`] rebuilds the full response deterministically;
12//! * [`structured::parse_structured`] turns a response into a typed value
13//! **all-or-nothing** (spec I18): schema validation with deny-unknown semantics,
14//! then typed deserialization; a single malformed act rejects the whole output;
15//! * [`error::ProviderError`] is the typed failure family, classified by
16//! [`error::RetryClass`] and free of secrets, request bodies and headers;
17//! * [`provider::ModelProvider`] is the trait every adapter implements against a
18//! configured [`capabilities::ModelProfile`]; capabilities are declared per
19//! provider-model pair, never inferred from the brand (spec §20.3);
20//! * [`router::PolicyRouter`] selects candidates by capability fit first, then
21//! tenant policy, then health and preference — and refuses to downgrade the
22//! structured-output requirement of a critical stage (spec §0 rule 9, §20.4);
23//! * [`fallback::execute_with_fallback`] tries candidates in order, retries by
24//! class, records every attempt and never merges partial outputs (spec §20.7).
25//!
26//! Concrete adapters live in sibling crates (`turnframe-provider-openai`, …) and
27//! prove themselves with the reusable [`conformance`] suite (feature
28//! `conformance`, spec §20.8).
29//!
30//! # Where the safety rules live
31//!
32//! | Rule | Where it is enforced |
33//! |------|----------------------|
34//! | Model arrays are all-or-nothing (I18) | [`structured`], [`stream::StreamAccumulator`] |
35//! | No silent capability downgrade (§0.9) | [`purpose::ModelPurpose::requirements`], [`router::PolicyRouter`] |
36//! | Provider failure cannot repeat effects (I17) | [`fallback::FallbackStage`] is a required parameter |
37//! | Secrets never reach prompts or logs (§25.2) | [`secret::ApiKey`], [`secret::Redactor`], error `Display` |
38//! | Record every provider attempt (§20.7) | [`fallback::ProviderAttempt`] |
39
40#![forbid(unsafe_code)]
41#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used, clippy::panic))]
42
43/// The crate README, compiled as a doc-test so its example cannot rot.
44#[cfg(doctest)]
45#[doc = include_str!("../README.md")]
46mod readme {}
47
48pub mod capabilities;
49#[cfg(feature = "conformance")]
50pub mod conformance;
51pub mod dialect;
52pub mod error;
53pub mod fallback;
54pub mod ids;
55pub mod provider;
56pub mod purpose;
57pub mod request;
58pub mod response;
59pub mod router;
60pub mod secret;
61pub mod stream;
62pub mod structured;
63pub mod testing;
64pub mod trace;
65
66/// The most used items, for `use turnframe_provider::prelude::*`.
67pub mod prelude {
68 pub use crate::capabilities::{
69 CapabilityMismatch, CapabilityRequirements, MicroCents, MissingCapability, ModelProfile,
70 ProviderCapabilities, StructuredOutputCapability, ToolCallingCapability,
71 };
72 pub use crate::error::{ErrorCode, ProviderError, ProviderErrorKind, RetryClass};
73 pub use crate::fallback::{
74 FallbackFailure, FallbackOptions, FallbackOutcome, FallbackStage, ProviderAttempt,
75 RetryPolicy, execute_with_fallback,
76 };
77 pub use crate::ids::{AttemptNumber, CallId, ModelKey, ModelRef, ProviderKey, RequestId};
78 pub use crate::provider::ModelProvider;
79 pub use crate::purpose::{LoggingPolicy, ModelPurpose, SafetyMode};
80 pub use crate::request::{
81 CacheHint, ContentPart, DocumentSource, ImageSource, Message, ModelRequest, OutputSpec,
82 RequestMetadata, Role, ToolCall, ToolChoice, ToolResult, ToolSpec,
83 };
84 pub use crate::response::{FinishReason, ModelResponse, ResponseWarning, TokenUsage};
85 pub use crate::router::{
86 Clock, PolicyRouter, ProviderCandidate, ProviderPool, ProviderPoolBuilder, ProviderRouter,
87 RoutingError, RoutingPolicy,
88 };
89 pub use crate::secret::{ApiKey, DefaultRedactor, Redactor};
90 pub use crate::stream::{ModelStream, StreamAccumulator, StreamEvent, reconstruct};
91 pub use crate::structured::{
92 CompiledSchema, SchemaCache, StructuredOutputError, parse_structured,
93 };
94}