#[non_exhaustive]pub struct ProviderCall {
pub system: Option<String>,
pub operation: Option<String>,
pub request_model: Option<String>,
pub temperature: Option<f64>,
pub response_id: Option<String>,
pub response_model: Option<String>,
pub finish_reasons: Vec<String>,
pub input_tokens: Option<u64>,
pub output_tokens: Option<u64>,
pub input_cached_tokens: Option<u64>,
}Expand description
One provider call, described with the OpenTelemetry GenAI semantic
conventions (gen_ai.*).
These are the attributes every LLM observability backend already reads —
Langfuse, Datadog LLM Observability, Phoenix, Braintrust — so a Turnframe
application shows up in them as a model call without any vendor adapter.
The keys live in crate::attrs so a provider crate and an application
spell them identically.
Token accounting is the part that is easy to get wrong, so it is explicit
here: ProviderCall::input_tokens is always recorded net of cached
tokens. A consumer that reads only that field sees the uncached prompt
cost; one that adds ProviderCall::input_cached_tokens sees the whole
prompt. Neither double counts. Use
ProviderCall::with_cached_usage when the provider reports a total and a
cached figure, and ProviderCall::with_usage when it already reports the
net one.
No member holds prompt or completion text: content is user data and travels
only through ContentRecorder, which is off by default.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.system: Option<String>Provider key, recorded as gen_ai.system.
operation: Option<String>Normalized request purpose, recorded as gen_ai.operation.name.
request_model: Option<String>Model asked for, recorded as gen_ai.request.model.
temperature: Option<f64>Sampling temperature, recorded as gen_ai.request.temperature.
response_id: Option<String>The provider’s identifier for the response.
response_model: Option<String>Model that actually answered, which is not always the one asked for.
finish_reasons: Vec<String>Why generation stopped.
input_tokens: Option<u64>Input tokens billed, net of input_cached_tokens.
output_tokens: Option<u64>Output tokens generated.
input_cached_tokens: Option<u64>Input tokens served from the provider’s prompt cache.
Implementations§
Source§impl ProviderCall
impl ProviderCall
Sourcepub fn new(
system: impl Into<String>,
operation: impl Into<String>,
request_model: impl Into<String>,
) -> ProviderCall
pub fn new( system: impl Into<String>, operation: impl Into<String>, request_model: impl Into<String>, ) -> ProviderCall
A call to system for operation with model.
Sourcepub fn from_attempt(attempt: &ProviderAttemptRecord) -> ProviderCall
pub fn from_attempt(attempt: &ProviderAttemptRecord) -> ProviderCall
Everything a persisted provider attempt already knows (spec §20.7).
Sourcepub fn with_temperature(self, temperature: f64) -> ProviderCall
pub fn with_temperature(self, temperature: f64) -> ProviderCall
Sets the requested sampling temperature.
Sourcepub fn with_response(
self,
response_id: impl Into<String>,
response_model: impl Into<String>,
) -> ProviderCall
pub fn with_response( self, response_id: impl Into<String>, response_model: impl Into<String>, ) -> ProviderCall
Sets the response identifier and the model that answered.
Sourcepub fn with_finish_reason(self, reason: impl Into<String>) -> ProviderCall
pub fn with_finish_reason(self, reason: impl Into<String>) -> ProviderCall
Adds a finish reason.
Sourcepub fn with_usage(self, input_tokens: u64, output_tokens: u64) -> ProviderCall
pub fn with_usage(self, input_tokens: u64, output_tokens: u64) -> ProviderCall
Records usage the provider already reports net of its prompt cache.
Sourcepub fn with_cached_usage(
self,
total_input_tokens: u64,
cached_tokens: u64,
output_tokens: u64,
) -> ProviderCall
pub fn with_cached_usage( self, total_input_tokens: u64, cached_tokens: u64, output_tokens: u64, ) -> ProviderCall
Records usage a provider reports as a total prompt size plus a cached figure, and stores the input tokens net of the cache.
use turnframe_telemetry::tracing::ProviderCall;
let call = ProviderCall::new("openai", "extract", "gpt-x")
.with_cached_usage(1_000, 800, 120);
// 200 uncached + 800 cached = the 1_000 the provider reported.
assert_eq!(call.input_tokens, Some(200));
assert_eq!(call.input_cached_tokens, Some(800));
assert_eq!(call.output_tokens, Some(120));Sourcepub fn total_input_tokens(&self) -> Option<u64>
pub fn total_input_tokens(&self) -> Option<u64>
The total prompt size the provider saw: net input plus cached.
Sourcepub fn attributes(&self) -> Vec<(&'static str, String)>
pub fn attributes(&self) -> Vec<(&'static str, String)>
The call as (attribute key, value) pairs in a stable order, omitting
what is unknown.
This is the exact set the span carries; it is a plain function so a test can assert on it without standing up a subscriber, and an adopter can rename the keys for a backend that wants its own spelling.
Trait Implementations§
Source§impl Clone for ProviderCall
impl Clone for ProviderCall
Source§fn clone(&self) -> ProviderCall
fn clone(&self) -> ProviderCall
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for ProviderCall
impl Debug for ProviderCall
Source§impl Default for ProviderCall
impl Default for ProviderCall
Source§fn default() -> ProviderCall
fn default() -> ProviderCall
Source§impl PartialEq for ProviderCall
impl PartialEq for ProviderCall
impl StructuralPartialEq for ProviderCall
Auto Trait Implementations§
impl Freeze for ProviderCall
impl RefUnwindSafe for ProviderCall
impl Send for ProviderCall
impl Sync for ProviderCall
impl Unpin for ProviderCall
impl UnsafeUnpin for ProviderCall
impl UnwindSafe for ProviderCall
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
Source§fn with_current_context(self) -> WithContext<Self> ⓘ
fn with_current_context(self) -> WithContext<Self> ⓘ
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more