mockforge_intelligence/handlers/behavioral_cloning/
probability.rs1use crate::behavioral_cloning::storage::{BehavioralCloningStateProvider, BehavioralCloningStore};
4use crate::behavioral_cloning::{EndpointProbabilityModel, ProbabilisticModel};
5use axum::extract::{Path, State};
6use axum::response::Json;
7use serde::{Deserialize, Serialize};
8use serde_json::{json, Value};
9
10#[derive(Debug, Deserialize)]
12pub struct BuildProbabilityModelRequest {
13 pub endpoint: String,
15 pub method: String,
17 #[serde(default)]
19 pub sample_limit: Option<u32>,
20}
21
22#[derive(Debug, Serialize)]
24pub struct ProbabilityModelResponse {
25 pub success: bool,
27 pub model: EndpointProbabilityModel,
29}
30
31pub async fn build_probability_model<S: BehavioralCloningStateProvider>(
35 State(state): State<S>,
36 Json(request): Json<BuildProbabilityModelRequest>,
37) -> Result<Json<Value>, String> {
38 let db = state.open_store().await?;
40
41 let limit = request.sample_limit.map(|l| l as i32);
43 let exchanges = db
44 .get_exchanges_for_endpoint(&request.endpoint, &request.method, limit)
45 .await
46 .map_err(|e| format!("Failed to query exchanges: {}", e))?;
47
48 if exchanges.is_empty() {
49 return Err(format!(
50 "No recorded traffic found for {} {}",
51 request.method, request.endpoint
52 ));
53 }
54
55 let data = super::probability_data::ModelData::from_exchanges(&exchanges);
56
57 let model = ProbabilisticModel::build_probability_model_from_data(
59 &request.endpoint,
60 &request.method,
61 &data.status_codes,
62 &data.latencies_ms,
63 &data.error_responses,
64 &data.request_payloads,
65 &data.response_payloads,
66 );
67
68 db.insert_endpoint_probability_model(&model)
70 .await
71 .map_err(|e| format!("Failed to store probability model: {}", e))?;
72
73 Ok(Json(json!({
74 "success": true,
75 "model": model
76 })))
77}
78
79pub async fn get_probability_model<S: BehavioralCloningStateProvider>(
83 Path((endpoint, method)): Path<(String, String)>,
84 State(state): State<S>,
85) -> Result<Json<Value>, String> {
86 let db = state.open_store().await?;
87
88 let model = db
89 .get_endpoint_probability_model(&endpoint, &method)
90 .await
91 .map_err(|e| format!("Failed to query probability model: {}", e))?
92 .ok_or_else(|| format!("No probability model found for {} {}", method, endpoint))?;
93
94 Ok(Json(json!({
95 "success": true,
96 "model": model
97 })))
98}
99
100pub async fn list_probability_models<S: BehavioralCloningStateProvider>(
104 State(state): State<S>,
105) -> Result<Json<Value>, String> {
106 let db = state.open_store().await?;
107
108 let models = db
109 .get_all_endpoint_probability_models()
110 .await
111 .map_err(|e| format!("Failed to query probability models: {}", e))?;
112
113 Ok(Json(json!({
114 "success": true,
115 "models": models,
116 "count": models.len()
117 })))
118}
119
120pub async fn sample_status_code<S: BehavioralCloningStateProvider>(
124 Path((endpoint, method)): Path<(String, String)>,
125 State(state): State<S>,
126) -> Result<Json<Value>, String> {
127 let db = state.open_store().await?;
128
129 let model = db
130 .get_endpoint_probability_model(&endpoint, &method)
131 .await
132 .map_err(|e| format!("Failed to query model: {}", e))?
133 .ok_or_else(|| format!("No probability model found for {} {}", method, endpoint))?;
134
135 let sampled_code = ProbabilisticModel::sample_status_code(&model);
136
137 Ok(Json(json!({
138 "success": true,
139 "endpoint": endpoint,
140 "method": method,
141 "status_code": sampled_code
142 })))
143}
144
145pub async fn sample_latency<S: BehavioralCloningStateProvider>(
149 Path((endpoint, method)): Path<(String, String)>,
150 State(state): State<S>,
151) -> Result<Json<Value>, String> {
152 let db = state.open_store().await?;
153
154 let model = db
155 .get_endpoint_probability_model(&endpoint, &method)
156 .await
157 .map_err(|e| format!("Failed to query model: {}", e))?
158 .ok_or_else(|| format!("No probability model found for {} {}", method, endpoint))?;
159
160 let sampled_latency = ProbabilisticModel::sample_latency(&model);
161
162 Ok(Json(json!({
163 "success": true,
164 "endpoint": endpoint,
165 "method": method,
166 "latency_ms": sampled_latency
167 })))
168}