reasoninglayer 0.1.2

Rust client SDK for the Reasoning Layer API
Documentation
//! Query DTOs — unification, structured search, validation.

use std::collections::BTreeMap;

use serde::{Deserialize, Serialize};

use super::terms::TermDto;
use super::values::ValueDto;

/// A query pattern with sort and features for structured search.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TermPatternDto {
    /// Sort UUID.
    pub sort_id: String,
    /// Features to match.
    pub features: BTreeMap<String, ValueDto>,
}

// ─── Unifiable ────────────────────────────────────────────────────────────────

/// Request to find terms unifiable with a given pattern.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnifiableQueryRequest {
    pub pattern: TermPatternDto,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_results: Option<u32>,
}

/// Response wrapper for unification queries.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct UnificationQueryResponse {
    #[serde(default)]
    pub results: Vec<TermDto>,
    #[serde(default)]
    pub count: u64,
}

// ─── By-sort / find-by-sort ───────────────────────────────────────────────────

/// Request to find all terms of a given sort.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BySortQueryRequest {
    pub sort_id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub include_subsorts: Option<bool>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_results: Option<u32>,
}

/// Request to find terms by sort ID or name, with optional feature filter.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct FindBySortRequest {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sort_id: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sort_name: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub filter: Option<BTreeMap<String, String>>,
}

/// Response wrapping a list of terms (e.g. for `findBySort`).
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct TermListResponse {
    #[serde(default)]
    pub terms: Vec<TermDto>,
    #[serde(default)]
    pub count: u64,
}

// ─── OSF search ───────────────────────────────────────────────────────────────

/// Request for structured (order-sorted feature) search.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OsfSearchRequest {
    pub pattern: TermPatternDto,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_entities: Option<u32>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub min_match_degree: Option<f64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub enable_unification: Option<bool>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub collection_id: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub namespace_id: Option<String>,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub term_ids: Vec<String>,
}

/// A matched entity in a structured search result.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MatchedEntityDto {
    pub term_id: String,
    pub sort_id: String,
    pub community_id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(default)]
    pub features: BTreeMap<String, String>,
    pub match_degree: f64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub match_reason: Option<String>,
}

/// A discovered relation between entities.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiscoveredRelationDto {
    pub relation_name: String,
    pub source_sort: String,
    pub target_sort: String,
    pub cardinality: String,
    pub confidence: f64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub inverse_name: Option<String>,
}

/// Information about missing data in a suspended query.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MissingInfoDto {
    pub kind: String,
    pub description: String,
    pub priority: u32,
}

/// A suggested way to resume/refine a suspended query.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResumptionOptionDto {
    pub id: String,
    pub description: String,
    pub expected_confidence_gain: f64,
}

/// Information about a suspended (residuated) query.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SuspendedQueryDto {
    pub confidence: f64,
    #[serde(default)]
    pub missing_info: Vec<MissingInfoDto>,
    #[serde(default)]
    pub resumption_options: Vec<ResumptionOptionDto>,
}

/// Execution statistics for a structured search.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct OsfSearchStatsDto {
    pub duration_us: u64,
    pub entities_matched: u64,
    pub relations_discovered: u64,
    pub communities_searched: u64,
    pub inference_steps: u64,
}

/// Response from structured search.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct OsfSearchResponse {
    #[serde(default)]
    pub entities: Vec<MatchedEntityDto>,
    #[serde(default)]
    pub relations: Vec<DiscoveredRelationDto>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub suspended: Option<SuspendedQueryDto>,
    #[serde(default)]
    pub stats: OsfSearchStatsDto,
}

// ─── Validate / unify ─────────────────────────────────────────────────────────

/// Request to validate a term against its sort's type witnesses.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidateTermRequest {
    pub term: TermPatternDto,
}

/// Request for validated unification of two terms.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidatedUnifyRequest {
    pub term1: TermPatternDto,
    pub term2: TermPatternDto,
}

// ─── Natural language ─────────────────────────────────────────────────────────

/// Translation mode for natural language queries.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum NlQueryMode {
    /// LLM-driven translation.
    #[default]
    Llm,
    /// Constraint-solver translation.
    Constraint,
    /// Cognitive-agent translation.
    Cognitive,
    /// TRIZ-invention translation.
    Triz,
}

/// A result item from a natural language query.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NlQueryResultItem {
    pub id: String,
    pub sort_name: String,
    #[serde(default)]
    pub features: BTreeMap<String, serde_json::Value>,
}

/// Tool call info returned by constraint-mode NL queries.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolCallInfo {
    pub name: String,
    pub arguments: serde_json::Value,
    pub confidence: f64,
}

/// Request for a natural language query.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NlQueryRequest {
    pub query: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub mode: Option<NlQueryMode>,
    pub tenant_id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub conversation_history: Option<Vec<serde_json::Value>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub session_id: Option<String>,
}

/// Response from a natural language query.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct NlQueryResponse {
    #[serde(default)]
    pub success: bool,
    #[serde(default)]
    pub query: String,
    #[serde(default = "default_nl_mode")]
    pub mode: NlQueryMode,
    #[serde(default)]
    pub results: Vec<NlQueryResultItem>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub explanation: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub generated_osf: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub error: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub agent_id: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub cognitive_summary: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub tool_call: Option<ToolCallInfo>,
}

fn default_nl_mode() -> NlQueryMode {
    NlQueryMode::Llm
}