mockforge_core/openapi/
response_trace.rs

1//! Response generation trace instrumentation
2//!
3//! This module provides helpers to instrument response generation
4//! and collect trace data for debugging and observability.
5
6use crate::openapi::response::ResponseGenerator;
7use crate::openapi::response_selection::ResponseSelectionMode;
8use crate::openapi::OpenApiSpec;
9use crate::reality_continuum::response_trace::ResponseGenerationTrace;
10use crate::Result;
11use openapiv3::Operation;
12use serde_json::Value;
13use std::time::Instant;
14
15/// Generate a response with trace collection
16///
17/// This function wraps the response generation and collects trace data
18/// about how the response was generated.
19///
20/// # Arguments
21/// * `spec` - The OpenAPI specification
22/// * `operation` - The operation to generate a response for
23/// * `status_code` - The HTTP status code
24/// * `content_type` - Optional content type
25/// * `expand_tokens` - Whether to expand template tokens
26/// * `scenario` - Optional scenario name
27/// * `selection_mode` - Response selection mode
28/// * `selector` - Optional response selector
29/// * `persona` - Optional persona for data generation
30///
31/// # Returns
32/// A tuple of (response_value, trace_data)
33pub fn generate_response_with_trace(
34    spec: &OpenApiSpec,
35    operation: &Operation,
36    status_code: u16,
37    content_type: Option<&str>,
38    expand_tokens: bool,
39    scenario: Option<&str>,
40    selection_mode: Option<ResponseSelectionMode>,
41    selector: Option<&crate::openapi::response_selection::ResponseSelector>,
42    persona: Option<&crate::intelligent_behavior::config::Persona>,
43) -> Result<(Value, ResponseGenerationTrace)> {
44    let start_time = Instant::now();
45    let mut trace = ResponseGenerationTrace::new();
46
47    // Record selection mode
48    let actual_mode = selection_mode.unwrap_or(ResponseSelectionMode::First);
49    trace.response_selection_mode = actual_mode;
50
51    // Record scenario if provided
52    if let Some(scenario_name) = scenario {
53        trace.selected_example = Some(scenario_name.to_string());
54    }
55
56    // Record template expansion setting
57    trace.add_metadata("expand_tokens".to_string(), serde_json::json!(expand_tokens));
58
59    // Record persona if provided
60    if let Some(p) = persona {
61        trace.add_metadata("persona_name".to_string(), serde_json::json!(p.name));
62    }
63
64    // Generate the response
65    let response = ResponseGenerator::generate_response_with_scenario_and_mode_and_persona(
66        spec,
67        operation,
68        status_code,
69        content_type,
70        expand_tokens,
71        scenario,
72        selection_mode,
73        selector,
74        persona,
75    )?;
76
77    // Record final payload
78    trace.set_final_payload(response.clone());
79
80    // Record generation time
81    let generation_time_ms = start_time.elapsed().as_millis() as u64;
82    trace.add_metadata("generation_time_ms".to_string(), serde_json::json!(generation_time_ms));
83
84    // Record operation ID if available
85    if let Some(operation_id) = &operation.operation_id {
86        trace.add_metadata("operation_id".to_string(), serde_json::json!(operation_id));
87    }
88
89    // Record status code
90    trace.add_metadata("status_code".to_string(), serde_json::json!(status_code));
91
92    // Try to determine which example was selected
93    // This is a simplified version - full implementation would need to
94    // instrument the actual selection logic
95    if let Some(sel) = selector {
96        if actual_mode == ResponseSelectionMode::Sequential {
97            let seq_index = sel.get_sequential_index();
98            trace.add_metadata("sequential_index".to_string(), serde_json::json!(seq_index));
99        }
100    }
101
102    // Record content type
103    if let Some(ct) = content_type {
104        trace.add_metadata("content_type".to_string(), serde_json::json!(ct));
105    }
106
107    Ok((response, trace))
108}