langfuse-client-base 0.21.0

Auto-generated Langfuse API client from OpenAPI specification
Documentation
#![allow(deprecated)]
/*
 * server
 *
 * ## Real-time data  The only real-time path to get tracing data is to ingest via OpenTelemetry (`POST /api/public/otel/v1/traces`) and retrieve via Observations API v2 (`GET /api/public/v2/observations`) and Metrics API v2 (`GET /api/public/v2/metrics`). Other public API write and read endpoints can delay data by about 10 minutes. Direct OpenTelemetry exporters must send the `x-langfuse-ingestion-version: 4` header; current Python and JS SDKs already do. See the [Public API docs](https://langfuse.com/docs/api-and-data-platform/features/public-api) and [real-time ingestion](https://langfuse.com/integrations/native/opentelemetry.md#real-time-ingestion).  ## Authentication  Authenticate with the API using [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication), get API keys in the project settings:  - username: Langfuse Public Key - password: Langfuse Secret Key  ## Exports  - OpenAPI spec: https://cloud.langfuse.com/generated/api/openapi.yml - Self-hosted deployments: interactive API reference at `/api/docs` and OpenAPI spec at `/api/openapi.yaml`
 *
 * The version of the OpenAPI document:
 *
 * Generated by: https://openapi-generator.tech
 */

use super::{configuration, ContentType, Error};
use crate::{apis::ResponseContent, models};
use serde::{de::Error as _, Deserialize, Serialize};
use timvw_rust_runtime;

/// struct for typed errors of method [`observations_get_many`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ObservationsGetManyError {
    Status400(serde_json::Value),
    Status401(serde_json::Value),
    Status403(serde_json::Value),
    Status404(serde_json::Value),
    Status405(serde_json::Value),
    UnknownValue(serde_json::Value),
}

/// Get a list of observations with cursor-based pagination and flexible field selection.  Together with OpenTelemetry ingestion and Metrics API v2, this is the only real-time read path. Other public API endpoints can delay data by about 10 minutes.  ## Cursor-based Pagination This endpoint uses cursor-based pagination for efficient traversal of large datasets. The cursor is returned in the response metadata and should be passed in subsequent requests to retrieve the next page of results. The `limit` parameter is a maximum: a page may contain fewer items than the requested limit, including zero items, while `meta.cursor` is present. Continue requesting pages until `meta.cursor` is absent. Requests without a lower start-time bound may search only from January 1, 2020.  ## Field Selection Use the `fields` parameter to control which observation fields are returned: - `core` - Always included: id, traceId, startTime, endTime, projectId, parentObservationId, type - `basic` - name, level, statusMessage, version, environment, bookmarked, public, userId, sessionId, isRootObservation - `time` - completionStartTime, createdAt, updatedAt - `io` - input, output - `metadata` - metadata (truncated to 200 chars by default, use `expandMetadata` to get full values) - `model` - model, internalModelId, modelParameters - `usage` - usageDetails, costDetails, totalCost, usagePricingTierName - `prompt` - promptId, promptName, promptVersion - `metrics` - latency, timeToFirstToken - `trace_context` - tags, release, traceName  If not specified, `core` and `basic` field groups are returned.  ## Filters Multiple filtering options are available via query parameters or the structured `filter` parameter. When using the `filter` parameter, it takes precedence over individual query parameter filters.
#[bon::builder]
pub async fn observations_get_many(
    configuration: &configuration::Configuration,
    fields: Option<&str>,
    expand_metadata: Option<&str>,
    limit: Option<i64>,
    cursor: Option<&str>,
    parse_io_as_json: Option<bool>,
    name: Option<&str>,
    user_id: Option<&str>,
    session_id: Option<&str>,
    r#type: Option<&str>,
    trace_id: Option<&str>,
    level: Option<models::ObservationLevel>,
    parent_observation_id: Option<&str>,
    is_root_observation: Option<bool>,
    environment: Option<Vec<String>>,
    from_start_time: Option<chrono::DateTime<chrono::FixedOffset>>,
    to_start_time: Option<chrono::DateTime<chrono::FixedOffset>>,
    version: Option<&str>,
    filter: Option<&str>,
) -> Result<models::ObservationsV2Response, Error<ObservationsGetManyError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_fields = fields;
    let p_query_expand_metadata = expand_metadata;
    let p_query_limit = limit;
    let p_query_cursor = cursor;
    let p_query_parse_io_as_json = parse_io_as_json;
    let p_query_name = name;
    let p_query_user_id = user_id;
    let p_query_session_id = session_id;
    let p_query_type = r#type;
    let p_query_trace_id = trace_id;
    let p_query_level = level;
    let p_query_parent_observation_id = parent_observation_id;
    let p_query_is_root_observation = is_root_observation;
    let p_query_environment = environment;
    let p_query_from_start_time = from_start_time;
    let p_query_to_start_time = to_start_time;
    let p_query_version = version;
    let p_query_filter = filter;

    let uri_str = format!("{}/api/public/v2/observations", configuration.base_path);
    let mut req_builder = configuration
        .client
        .request(timvw_rust_runtime::Method::GET, &uri_str);

    if let Some(ref param_value) = p_query_fields {
        req_builder = req_builder.query(&[("fields", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_expand_metadata {
        req_builder = req_builder.query(&[("expandMetadata", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_limit {
        req_builder = req_builder.query(&[("limit", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_cursor {
        req_builder = req_builder.query(&[("cursor", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_parse_io_as_json {
        req_builder = req_builder.query(&[("parseIoAsJson", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_name {
        req_builder = req_builder.query(&[("name", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_user_id {
        req_builder = req_builder.query(&[("userId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_session_id {
        req_builder = req_builder.query(&[("sessionId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_type {
        req_builder = req_builder.query(&[("type", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_trace_id {
        req_builder = req_builder.query(&[("traceId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_level {
        req_builder = req_builder.query(&[("level", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_parent_observation_id {
        req_builder = req_builder.query(&[("parentObservationId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_is_root_observation {
        req_builder = req_builder.query(&[("isRootObservation", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_environment {
        let items: Vec<String> = param_value.iter().map(|p| p.to_string()).collect();
        for item in items {
            req_builder = req_builder.query(&[("environment", item)]);
        }
    }
    if let Some(ref param_value) = p_query_from_start_time {
        req_builder = req_builder.query(&[("fromStartTime", &param_value.to_rfc3339())]);
    }
    if let Some(ref param_value) = p_query_to_start_time {
        req_builder = req_builder.query(&[("toStartTime", &param_value.to_rfc3339())]);
    }
    if let Some(ref param_value) = p_query_version {
        req_builder = req_builder.query(&[("version", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_filter {
        req_builder = req_builder.query(&[("filter", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder =
            req_builder.header(timvw_rust_runtime::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref auth_conf) = configuration.basic_auth {
        req_builder = req_builder.basic_auth(auth_conf.0.to_owned(), auth_conf.1.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ObservationsV2Response`"))),
            ContentType::Unsupported(unknown_type) => Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::ObservationsV2Response`")))),
        }
    } else {
        let headers = resp.headers().clone();
        let content = resp.text().await?;
        let entity: Option<ObservationsGetManyError> = match status.as_u16() {
            400 => serde_json::from_str(&content)
                .ok()
                .map(ObservationsGetManyError::Status400),
            401 => serde_json::from_str(&content)
                .ok()
                .map(ObservationsGetManyError::Status401),
            403 => serde_json::from_str(&content)
                .ok()
                .map(ObservationsGetManyError::Status403),
            404 => serde_json::from_str(&content)
                .ok()
                .map(ObservationsGetManyError::Status404),
            405 => serde_json::from_str(&content)
                .ok()
                .map(ObservationsGetManyError::Status405),
            _ => None,
        }
        .or_else(|| {
            serde_json::from_str(&content)
                .ok()
                .map(ObservationsGetManyError::UnknownValue)
        });
        Err(Error::ResponseError(Box::new(ResponseContent {
            status,
            content,
            entity,
            headers,
        })))
    }
}