1#![allow(deprecated)]
13
14use crate::ai_studio::{
15 api_critique::ApiCritiqueEngine, artifact_freezer::ArtifactFreezer,
16 behavioral_simulator::BehavioralSimulator, config::DeterministicModeConfig,
17 system_generator::SystemGenerator,
18};
19use crate::intelligent_behavior::IntelligentBehaviorConfig;
20use axum::{
21 extract::{Path, State},
22 http::StatusCode,
23 response::Json,
24 routing::post,
25 Router,
26};
27use mockforge_foundation::ai_studio_types::{
28 CreateAgentRequest, CritiqueRequest, FreezeMetadata, FreezeRequest, SimulateBehaviorRequest,
29 SystemGenerationRequest,
30};
31use serde::{Deserialize, Serialize};
32use std::collections::HashMap;
33use std::sync::Arc;
34use tokio::sync::{Mutex, RwLock};
35use tracing::{error, info, warn};
36
37#[derive(Clone)]
39pub struct AiStudioState {
40 pub critique_engine: Arc<ApiCritiqueEngine>,
42 pub system_generator: Arc<SystemGenerator>,
44 pub behavioral_simulator: Arc<Mutex<BehavioralSimulator>>,
46 pub artifact_freezer: Arc<ArtifactFreezer>,
48 pub config: IntelligentBehaviorConfig,
50 pub deterministic_config: Option<DeterministicModeConfig>,
52 pub workspace_id: Option<String>,
54 pub system_storage:
56 Arc<RwLock<HashMap<String, mockforge_foundation::ai_studio_types::GeneratedSystem>>>,
57}
58
59impl AiStudioState {
60 pub fn new(config: IntelligentBehaviorConfig) -> Self {
62 let critique_engine = Arc::new(ApiCritiqueEngine::new(config.clone()));
63 let system_generator = Arc::new(SystemGenerator::new(config.clone()));
64 let behavioral_simulator = Arc::new(Mutex::new(BehavioralSimulator::new(config.clone())));
65 let artifact_freezer = Arc::new(ArtifactFreezer::new());
66 Self {
67 critique_engine,
68 system_generator,
69 behavioral_simulator,
70 artifact_freezer,
71 config,
72 deterministic_config: None,
73 workspace_id: None,
74 system_storage: Arc::new(RwLock::new(HashMap::new())),
75 }
76 }
77
78 pub fn with_workspace(
80 mut self,
81 workspace_id: String,
82 deterministic_config: Option<DeterministicModeConfig>,
83 ) -> Self {
84 self.workspace_id = Some(workspace_id);
85 self.deterministic_config = deterministic_config;
86 self
87 }
88}
89
90#[derive(Debug, Deserialize, Serialize)]
92pub struct ApiCritiqueRequest {
93 pub schema: serde_json::Value,
95
96 pub schema_type: String,
98
99 #[serde(default)]
102 pub focus_areas: Vec<String>,
103
104 pub workspace_id: Option<String>,
106}
107
108#[derive(Debug, Serialize)]
110pub struct ApiCritiqueResponse {
111 pub critique: crate::ai_studio::api_critique::ApiCritique,
113
114 #[serde(skip_serializing_if = "Option::is_none")]
116 pub artifact_id: Option<String>,
117
118 pub frozen: bool,
120}
121
122pub async fn api_critique_handler(
126 State(state): State<AiStudioState>,
127 Json(request): Json<ApiCritiqueRequest>,
128) -> Result<Json<ApiCritiqueResponse>, StatusCode> {
129 info!("API critique request received for schema type: {}", request.schema_type);
130
131 let critique_request = CritiqueRequest {
133 schema: request.schema,
134 schema_type: request.schema_type,
135 focus_areas: request.focus_areas,
136 workspace_id: request.workspace_id.or_else(|| state.workspace_id.clone()),
137 };
138
139 let critique = match state.critique_engine.analyze(&critique_request).await {
141 Ok(c) => c,
142 Err(e) => {
143 error!("Failed to generate API critique: {}", e);
144 return Err(StatusCode::INTERNAL_SERVER_ERROR);
145 }
146 };
147
148 let critique_json = match serde_json::to_value(&critique) {
150 Ok(v) => v,
151 Err(e) => {
152 error!("Failed to serialize critique: {}", e);
153 return Err(StatusCode::INTERNAL_SERVER_ERROR);
154 }
155 };
156
157 let freeze_request = FreezeRequest {
159 artifact_type: "api_critique".to_string(),
160 content: critique_json,
161 format: "json".to_string(),
162 path: None,
163 metadata: Some(FreezeMetadata {
164 llm_provider: Some(state.config.behavior_model.llm_provider.clone()),
165 llm_model: Some(state.config.behavior_model.model.clone()),
166 llm_version: None,
167 prompt_hash: None,
168 output_hash: None,
169 original_prompt: None,
170 }),
171 };
172
173 let frozen_artifact = match state.artifact_freezer.freeze(&freeze_request).await {
174 Ok(a) => a,
175 Err(e) => {
176 error!("Failed to freeze critique artifact: {}", e);
177 return Err(StatusCode::INTERNAL_SERVER_ERROR);
178 }
179 };
180
181 info!(
182 "API critique completed. Artifact path: {}, Tokens used: {:?}, Cost: ${:.4}",
183 frozen_artifact.path,
184 critique.tokens_used,
185 critique.cost_usd.unwrap_or(0.0)
186 );
187
188 Ok(Json(ApiCritiqueResponse {
189 critique,
190 artifact_id: Some(frozen_artifact.path),
191 frozen: true,
192 }))
193}
194
195#[derive(Debug, Deserialize)]
197pub struct SystemGenerationHttpRequest {
198 pub description: String,
200
201 #[serde(default)]
203 pub output_formats: Vec<String>,
204
205 pub workspace_id: Option<String>,
207
208 pub system_id: Option<String>,
210}
211
212#[derive(Debug, Serialize)]
214pub struct SystemGenerationResponse {
215 pub system: mockforge_foundation::ai_studio_types::GeneratedSystem,
217}
218
219#[derive(Debug, Deserialize)]
221pub struct ApplySystemRequest {
222 #[serde(default)]
224 pub artifact_ids: Option<Vec<String>>,
225}
226
227#[derive(Debug, Serialize)]
229pub struct ApplySystemResponse {
230 pub applied: crate::ai_studio::system_generator::AppliedSystem,
232}
233
234#[derive(Debug, Deserialize)]
236pub struct FreezeArtifactsRequest {
237 pub artifact_ids: Vec<String>,
239}
240
241#[derive(Debug, Serialize)]
243pub struct FreezeArtifactsResponse {
244 pub frozen_paths: Vec<String>,
246}
247
248pub async fn generate_system_handler(
252 State(state): State<AiStudioState>,
253 Json(request): Json<SystemGenerationHttpRequest>,
254) -> Result<Json<SystemGenerationResponse>, StatusCode> {
255 info!("System generation request received");
256
257 let generation_request = SystemGenerationRequest {
258 description: request.description,
259 output_formats: request.output_formats,
260 workspace_id: request.workspace_id.or_else(|| state.workspace_id.clone()),
261 system_id: request.system_id,
262 };
263
264 let system = match state
265 .system_generator
266 .generate(&generation_request, state.deterministic_config.as_ref())
267 .await
268 {
269 Ok(s) => s,
270 Err(e) => {
271 error!("Failed to generate system: {}", e);
272 return Err(StatusCode::INTERNAL_SERVER_ERROR);
273 }
274 };
275
276 {
278 let mut storage = state.system_storage.write().await;
279 storage.insert(system.system_id.clone(), system.clone());
280 }
281
282 info!(
283 "System generation completed. System ID: {}, Version: {}, Status: {}, Tokens: {:?}, Cost: ${:.4}",
284 system.system_id,
285 system.version,
286 system.status,
287 system.tokens_used,
288 system.cost_usd.unwrap_or(0.0)
289 );
290
291 Ok(Json(SystemGenerationResponse { system }))
292}
293
294pub async fn apply_system_handler(
298 State(state): State<AiStudioState>,
299 Path(system_id): Path<String>,
300 Json(request): Json<ApplySystemRequest>,
301) -> Result<Json<ApplySystemResponse>, StatusCode> {
302 info!("Apply system request received for system: {}", system_id);
303
304 let system = {
306 let storage = state.system_storage.read().await;
307 storage.get(&system_id).cloned()
308 };
309
310 let system = match system {
311 Some(s) => s,
312 None => {
313 warn!("System not found: {}", system_id);
314 return Err(StatusCode::NOT_FOUND);
315 }
316 };
317
318 let applied = match state
320 .system_generator
321 .apply_system_design(
322 &system,
323 state.deterministic_config.as_ref(),
324 request.artifact_ids.clone(),
325 )
326 .await
327 {
328 Ok(a) => a,
329 Err(e) => {
330 error!("Failed to apply system design: {}", e);
331 return Err(StatusCode::INTERNAL_SERVER_ERROR);
332 }
333 };
334
335 if applied.frozen {
337 let mut storage = state.system_storage.write().await;
338 if let Some(stored_system) = storage.get_mut(&system_id) {
339 stored_system.status = "frozen".to_string();
340 }
341 }
342
343 info!(
344 "System design applied. System ID: {}, Applied artifacts: {}, Frozen: {}",
345 applied.system_id,
346 applied.applied_artifacts.len(),
347 applied.frozen
348 );
349
350 Ok(Json(ApplySystemResponse { applied }))
351}
352
353pub async fn freeze_artifacts_handler(
357 State(state): State<AiStudioState>,
358 Path(system_id): Path<String>,
359 Json(request): Json<FreezeArtifactsRequest>,
360) -> Result<Json<FreezeArtifactsResponse>, StatusCode> {
361 info!(
362 "Freeze artifacts request received for system: {}, artifacts: {:?}",
363 system_id, request.artifact_ids
364 );
365
366 let system = {
368 let storage = state.system_storage.read().await;
369 storage.get(&system_id).cloned()
370 };
371
372 let system = match system {
373 Some(s) => s,
374 None => {
375 warn!("System not found: {}", system_id);
376 return Err(StatusCode::NOT_FOUND);
377 }
378 };
379
380 let frozen_paths = match state
382 .system_generator
383 .freeze_artifacts(&system, request.artifact_ids.clone())
384 .await
385 {
386 Ok(paths) => paths,
387 Err(e) => {
388 error!("Failed to freeze artifacts: {}", e);
389 return Err(StatusCode::INTERNAL_SERVER_ERROR);
390 }
391 };
392
393 if !frozen_paths.is_empty() {
395 let mut storage = state.system_storage.write().await;
396 if let Some(stored_system) = storage.get_mut(&system_id) {
397 let all_frozen = stored_system
399 .artifacts
400 .values()
401 .all(|artifact| request.artifact_ids.contains(&artifact.artifact_id));
402 if all_frozen {
403 stored_system.status = "frozen".to_string();
404 }
405 }
406 }
407
408 info!(
409 "Artifacts frozen. System ID: {}, Frozen paths: {}",
410 system_id,
411 frozen_paths.len()
412 );
413
414 Ok(Json(FreezeArtifactsResponse { frozen_paths }))
415}
416
417#[derive(Debug, Deserialize)]
419pub struct CreateAgentHttpRequest {
420 pub persona_id: Option<String>,
422
423 pub behavior_policy: Option<String>,
425
426 pub generate_persona: bool,
428
429 pub workspace_id: Option<String>,
431}
432
433#[derive(Debug, Serialize)]
435pub struct CreateAgentResponse {
436 pub agent: mockforge_foundation::ai_studio_types::NarrativeAgent,
438}
439
440#[derive(Debug, Deserialize)]
442pub struct SimulateBehaviorHttpRequest {
443 pub agent_id: Option<String>,
445
446 pub persona_id: Option<String>,
448
449 pub current_state: mockforge_foundation::ai_studio_types::AppState,
451
452 pub trigger_event: Option<String>,
454
455 pub workspace_id: Option<String>,
457}
458
459#[axum::debug_handler]
463pub async fn create_agent_handler(
464 State(_state): State<AiStudioState>,
465 Json(_request): Json<CreateAgentHttpRequest>,
466) -> Result<Json<CreateAgentResponse>, StatusCode> {
467 info!("Create agent request received");
468 let state = _state;
469 let request = _request;
470
471 let create_request = CreateAgentRequest {
472 persona_id: request.persona_id,
473 behavior_policy: request.behavior_policy,
474 generate_persona: request.generate_persona,
475 workspace_id: request.workspace_id.or_else(|| state.workspace_id.clone()),
476 };
477
478 let mut simulator = state.behavioral_simulator.lock().await;
479 let agent = match simulator.create_agent(&create_request).await {
480 Ok(a) => a,
481 Err(e) => {
482 error!("Failed to create agent: {}", e);
483 return Err(StatusCode::INTERNAL_SERVER_ERROR);
484 }
485 };
486
487 info!("Agent created: {}", agent.agent_id);
488
489 Ok(Json(CreateAgentResponse { agent }))
490}
491
492#[axum::debug_handler]
496pub async fn simulate_behavior_handler(
497 State(_state): State<AiStudioState>,
498 Json(_request): Json<SimulateBehaviorHttpRequest>,
499) -> Result<Json<mockforge_foundation::ai_studio_types::SimulateBehaviorResponse>, StatusCode> {
500 info!("Simulate behavior request received");
501 let state = _state;
502 let request = _request;
503
504 let simulate_request = SimulateBehaviorRequest {
505 agent_id: request.agent_id,
506 persona_id: request.persona_id,
507 current_state: request.current_state,
508 trigger_event: request.trigger_event,
509 workspace_id: request.workspace_id.or_else(|| state.workspace_id.clone()),
510 };
511
512 let mut simulator = state.behavioral_simulator.lock().await;
513 let response = match simulator.simulate_behavior(&simulate_request).await {
514 Ok(r) => r,
515 Err(e) => {
516 error!("Failed to simulate behavior: {}", e);
517 return Err(StatusCode::INTERNAL_SERVER_ERROR);
518 }
519 };
520
521 info!(
522 "Behavior simulation completed. Intention: {:?}, Tokens: {:?}, Cost: ${:.4}",
523 response.intention,
524 response.tokens_used,
525 response.cost_usd.unwrap_or(0.0)
526 );
527
528 Ok(Json(response))
529}
530
531pub fn ai_studio_router(state: AiStudioState) -> Router {
533 let router = Router::new()
534 .route("/api-critique", post(api_critique_handler))
535 .route("/generate-system", post(generate_system_handler))
536 .route("/system/{system_id}/apply", post(apply_system_handler))
537 .route("/system/{system_id}/freeze", post(freeze_artifacts_handler))
538 .route("/simulate-behavior/create-agent", post(create_agent_handler))
539 .route("/simulate-behavior", post(simulate_behavior_handler));
540 router.with_state(state)
541}
542
543#[cfg(test)]
544mod tests {
545 use super::*;
546 use mockforge_foundation::intelligent_behavior::BehaviorModelConfig;
547
548 fn create_test_state() -> AiStudioState {
549 let config = IntelligentBehaviorConfig {
550 behavior_model: BehaviorModelConfig {
551 llm_provider: "ollama".to_string(),
552 model: "llama2".to_string(),
553 api_endpoint: Some("http://localhost:11434/api/chat".to_string()),
554 api_key: None,
555 temperature: 0.7,
556 max_tokens: 2000,
557 rules: crate::intelligent_behavior::types::BehaviorRules::default(),
558 },
559 ..Default::default()
560 };
561 AiStudioState::new(config)
562 }
563
564 #[test]
565 fn test_ai_studio_state_creation() {
566 let state = create_test_state();
567 assert!(state.workspace_id.is_none());
568 assert!(state.deterministic_config.is_none());
569 }
570
571 #[test]
572 fn test_api_critique_request_serialization() {
573 let request = ApiCritiqueRequest {
574 schema: serde_json::json!({"openapi": "3.0.0"}),
575 schema_type: "openapi".to_string(),
576 focus_areas: vec!["anti-patterns".to_string()],
577 workspace_id: None,
578 };
579
580 let json = serde_json::to_string(&request).unwrap();
581 assert!(json.contains("openapi"));
582 assert!(json.contains("anti-patterns"));
583 }
584}