use crate::openapi::response_selection::ResponseSelectionMode;
use crate::schema_diff::ValidationError;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResponseGenerationTrace {
#[serde(skip_serializing_if = "Option::is_none")]
pub template_path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fixture_path: Option<String>,
pub response_selection_mode: ResponseSelectionMode,
#[serde(skip_serializing_if = "Option::is_none")]
pub selected_example: Option<String>,
#[serde(default)]
pub persona_graph_nodes: Vec<PersonaGraphNodeUsage>,
#[serde(default)]
pub rules_executed: Vec<RuleExecution>,
#[serde(default)]
pub template_expansions: Vec<TemplateExpansion>,
#[serde(skip_serializing_if = "Option::is_none")]
pub blending_decision: Option<BlendingDecision>,
#[serde(skip_serializing_if = "Option::is_none")]
pub final_payload: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub schema_validation_diff: Option<Vec<ValidationError>>,
#[serde(default)]
pub metadata: HashMap<String, Value>,
}
impl Default for ResponseGenerationTrace {
fn default() -> Self {
Self {
template_path: None,
fixture_path: None,
response_selection_mode: ResponseSelectionMode::First,
selected_example: None,
persona_graph_nodes: Vec::new(),
rules_executed: Vec::new(),
template_expansions: Vec::new(),
blending_decision: None,
final_payload: None,
schema_validation_diff: None,
metadata: HashMap::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PersonaGraphNodeUsage {
pub persona_id: String,
pub entity_type: String,
pub usage_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub relationship_path: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RuleExecution {
pub name: String,
pub rule_type: String,
pub condition_matched: bool,
#[serde(default)]
pub actions_executed: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub execution_time_ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemplateExpansion {
pub template: String,
pub value: Value,
pub source: String,
pub step: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BlendingDecision {
pub blend_ratio: f64,
pub ratio_source: String,
pub blended: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub merge_strategy: Option<String>,
#[serde(default)]
pub field_decisions: Vec<FieldBlendingDecision>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FieldBlendingDecision {
pub field_path: String,
pub field_ratio: f64,
pub value_source: String,
}
impl ResponseGenerationTrace {
pub fn new() -> Self {
Self::default()
}
pub fn add_persona_node(&mut self, usage: PersonaGraphNodeUsage) {
self.persona_graph_nodes.push(usage);
}
pub fn add_rule_execution(&mut self, execution: RuleExecution) {
self.rules_executed.push(execution);
}
pub fn add_template_expansion(&mut self, expansion: TemplateExpansion) {
self.template_expansions.push(expansion);
}
pub fn set_blending_decision(&mut self, decision: BlendingDecision) {
self.blending_decision = Some(decision);
}
pub fn add_metadata(&mut self, key: String, value: Value) {
self.metadata.insert(key, value);
}
pub fn set_final_payload(&mut self, payload: Value) {
self.final_payload = Some(payload);
}
pub fn set_schema_validation_diff(&mut self, diff: Vec<ValidationError>) {
self.schema_validation_diff = Some(diff);
}
}