use std::{collections::HashMap, ffi::c_void};
use super::{llm_call::LLMCallKind, RawObject, RawObjectTrait};
use crate::{
baml_unreachable,
codec::BamlDecode,
error::BamlError,
proto::baml_cffi_v1::{BamlObjectType, CffiValueHolder},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogType {
Call,
Stream,
}
impl BamlDecode for LogType {
fn baml_decode(holder: &CffiValueHolder) -> Result<Self, BamlError> {
let s = String::baml_decode(holder)?;
match s.as_str() {
"call" => Ok(LogType::Call),
"stream" => Ok(LogType::Stream),
other => Err(BamlError::internal(format!("unknown log type: {other}"))),
}
}
}
define_raw_object_wrapper! {
Usage => ObjectUsage
}
impl Usage {
pub fn input_tokens(&self) -> i64 {
self.raw.call_method("input_tokens", ())
}
pub fn output_tokens(&self) -> i64 {
self.raw.call_method("output_tokens", ())
}
pub fn cached_input_tokens(&self) -> Option<i64> {
self.raw.call_method("cached_input_tokens", ())
}
}
define_raw_object_wrapper! {
Timing => ObjectTiming
}
impl Timing {
pub fn start_time_utc_ms(&self) -> i64 {
self.raw.call_method("start_time_utc_ms", ())
}
pub fn duration_ms(&self) -> Option<i64> {
self.raw.call_method("duration_ms", ())
}
}
define_raw_object_wrapper! {
StreamTiming => ObjectStreamTiming
}
impl StreamTiming {
pub fn start_time_utc_ms(&self) -> i64 {
self.raw.call_method("start_time_utc_ms", ())
}
pub fn duration_ms(&self) -> Option<i64> {
self.raw.call_method("duration_ms", ())
}
}
define_raw_object_wrapper! {
FunctionLog => ObjectFunctionLog
}
impl FunctionLog {
pub fn id(&self) -> String {
self.raw.call_method("id", ())
}
pub fn function_name(&self) -> String {
self.raw.call_method("function_name", ())
}
pub fn log_type(&self) -> LogType {
self.raw.call_method("log_type", ())
}
pub fn raw_llm_response(&self) -> Option<String> {
self.raw.call_method("raw_llm_response", ())
}
pub fn tags(&self) -> HashMap<String, String> {
self.raw.call_method("tags", ())
}
pub fn usage(&self) -> Usage {
self.raw
.call_method_for_object("usage", ())
.unwrap_or_else(|e| baml_unreachable!("Failed to get usage: {e}"))
}
pub fn timing(&self) -> Timing {
self.raw
.call_method_for_object("timing", ())
.unwrap_or_else(|e| baml_unreachable!("Failed to get timing: {e}"))
}
pub fn calls(&self) -> Vec<LLMCallKind> {
self.raw
.call_method_for_objects("calls", ())
.unwrap_or_else(|e| baml_unreachable!("Failed to get calls: {e}"))
}
pub fn selected_call(&self) -> Option<LLMCallKind> {
self.raw
.call_method_for_object_optional("selected_call", ())
.unwrap_or_else(|e| baml_unreachable!("Failed to get selected call: {e}"))
}
}
define_raw_object_wrapper! {
Collector => ObjectCollector
}
impl std::fmt::Debug for Collector {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Collector(name={})", self.name())
}
}
impl Collector {
pub fn new(runtime: *const c_void, name: &str) -> Self {
let raw = RawObject::new(runtime, BamlObjectType::ObjectCollector, ("name", name))
.unwrap_or_else(|e| baml_unreachable!("Failed to create Collector: {e}"));
Self { raw }
}
pub fn name(&self) -> String {
self.raw.call_method("name", ())
}
pub fn clear(&self) -> i64 {
self.raw.call_method("clear", ())
}
pub fn usage(&self) -> Usage {
self.raw
.call_method_for_object("usage", ())
.unwrap_or_else(|e| baml_unreachable!("Failed to get usage: {e}"))
}
pub fn logs(&self) -> Vec<FunctionLog> {
self.raw
.call_method_for_objects("logs", ())
.unwrap_or_else(|e| baml_unreachable!("Failed to get logs: {e}"))
}
pub fn last(&self) -> Option<FunctionLog> {
self.raw
.call_method_for_object_optional("last", ())
.unwrap_or_else(|e| baml_unreachable!("Failed to get last log: {e}"))
}
pub fn get_by_id(&self, id: &str) -> Option<FunctionLog> {
self.raw
.call_method_for_object("id", ("function_id", id))
.ok()
}
}