reasoninglayer 0.1.2

Rust client SDK for the Reasoning Layer API
Documentation
//! Causal reasoning DTOs (Pearl's hierarchy).

use std::collections::BTreeMap;

use serde::{Deserialize, Serialize};

// ─── Supporting types ─────────────────────────────────────────────────────────

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CausalEdgeDto {
    pub cause: String,
    pub certainty: f64,
    pub effect: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub mechanism: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CausalChainDto {
    pub certainty: f64,
    pub chain: Vec<String>,
    pub length: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RootCauseDto {
    pub cause: String,
    pub certainty: f64,
    pub path: Vec<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub via: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProofNodeDto {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub certainty: Option<f64>,
    #[serde(default)]
    pub children: Vec<String>,
    pub depth: u32,
    pub explanation: String,
    pub id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub parent_id: Option<String>,
    pub rule_name: String,
    pub step_type: String,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ProofStatisticsDto {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub duration_ms: Option<u64>,
    pub max_depth: u32,
    pub rules_applied: u32,
    pub total_nodes: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CausalProofTreeDto {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub dot_format: Option<String>,
    #[serde(default)]
    pub nodes: Vec<ProofNodeDto>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub root_id: Option<String>,
    pub statistics: ProofStatisticsDto,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CausalRelationshipDto {
    pub cause: String,
    pub effect: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QueryResultDto {
    #[serde(default)]
    pub certainties: Vec<f64>,
    #[serde(default)]
    pub values: Vec<serde_json::Value>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CounterfactualTraceDto {
    pub abduction: String,
    pub action: String,
    pub prediction: String,
}

// ─── Requests ─────────────────────────────────────────────────────────────────

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CausalAncestorRequest {
    pub ancestor: String,
    pub descendant: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CausesRequest {
    pub cause: String,
    pub effect: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CounterfactualRequest {
    pub antecedent_value: serde_json::Value,
    pub antecedent_variable: String,
    pub consequent_variable: String,
    #[serde(default)]
    pub evidence: BTreeMap<String, serde_json::Value>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DSeparatedRequest {
    pub conditioning_set: Vec<String>,
    pub x: String,
    pub y: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InterventionRequest {
    pub query_variable: String,
    pub value: serde_json::Value,
    pub variable: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AddCausalRelationRequest {
    pub cause: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub certainty: Option<f64>,
    pub effect: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub mechanism: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RootCauseAnalysisRequest {
    pub effect: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_depth: Option<u32>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidateDidRequest {
    /// Variable to check for difference-in-differences validity.
    pub treatment: String,
    /// Outcome variable.
    pub outcome: String,
    /// Control variables.
    #[serde(default)]
    pub controls: Vec<String>,
}

// ─── Responses ────────────────────────────────────────────────────────────────

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CausalAncestorResponse {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub chain_certainty: Option<f64>,
    pub explanation: String,
    pub is_ancestor: bool,
    #[serde(default)]
    pub path: Vec<String>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CausesResponse {
    pub causes: bool,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub certainty: Option<f64>,
    pub explanation: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CounterfactualResponse {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub counterfactual_value: Option<serde_json::Value>,
    #[serde(default)]
    pub exogenous_values: BTreeMap<String, serde_json::Value>,
    pub explanation: String,
    pub query: String,
    pub success: bool,
    pub trace: CounterfactualTraceDto,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct DSeparatedResponse {
    #[serde(default)]
    pub active_paths: Vec<Vec<String>>,
    pub d_separated: bool,
    pub explanation: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InterventionResponse {
    pub disabled_rules_count: u32,
    pub explanation: String,
    pub intervened_variable: String,
    pub intervention_value: serde_json::Value,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub query_result: Option<QueryResultDto>,
    pub success: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AddCausalRelationResponse {
    pub message: String,
    pub rule_id: String,
    pub success: bool,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct RootCauseAnalysisResponse {
    #[serde(default)]
    pub causal_chains: Vec<CausalChainDto>,
    pub effect: String,
    #[serde(default)]
    pub root_causes: Vec<RootCauseDto>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RootCauseWithProofResponse {
    #[serde(default)]
    pub causal_chains: Vec<CausalChainDto>,
    pub effect: String,
    pub proof_tree: CausalProofTreeDto,
    #[serde(default)]
    pub root_causes: Vec<RootCauseDto>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct GetCausalModelResponse {
    #[serde(default)]
    pub edges: Vec<CausalEdgeDto>,
    pub total_relations: u32,
    #[serde(default)]
    pub variables: Vec<String>,
}