| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- """Adaptive Loop router (P3-M5).
- Endpoints for the complete adaptive simulation closed loop,
- integrating all P3 components.
- """
- from typing import Dict, Any, Optional, List
- from fastapi import APIRouter, HTTPException
- from pydantic import BaseModel, Field
- from ..services.adaptive_loop import (
- AdaptiveLoop, create_loop, get_loop, list_loops, LoopPhase
- )
- router = APIRouter(prefix="/api/adaptive", tags=["Adaptive Loop"])
- class CreateLoopRequest(BaseModel):
- """Request to create a new adaptive loop."""
- user_requirement: str = Field(..., description="Natural language simulation requirement")
- total_budget: int = Field(default=80, ge=10, le=500)
- batch_size: int = Field(default=4, ge=1, le=16)
- class ReportResultsRequest(BaseModel):
- """Request to report simulation results."""
- point_results: List[Dict[str, Any]] = Field(..., description="List of {point_id, metrics, status}")
- @router.post("/loops")
- def create_new_loop(request: CreateLoopRequest):
- """Create a new adaptive simulation loop.
- Initializes the loop with a user requirement. The loop will
- proceed through: plan generation -> L0 screening -> search init
- -> batch selection -> simulation -> analysis -> experience update.
- """
- loop = create_loop(
- user_requirement=request.user_requirement,
- total_budget=request.total_budget,
- batch_size=request.batch_size,
- )
- return {
- "loop_id": loop.loop_id,
- "phase": loop.phase.value,
- "message": "Loop created. Call /loops/{id}/generate-plan to start.",
- }
- @router.get("/loops")
- def get_all_loops():
- """List all active adaptive loops."""
- return {"loops": list_loops()}
- @router.get("/loops/{loop_id}")
- def get_loop_state(loop_id: str):
- """Get complete state of an adaptive loop."""
- loop = get_loop(loop_id)
- if not loop:
- raise HTTPException(status_code=404, detail=f"Loop {loop_id} not found")
- return loop.get_state()
- @router.post("/loops/{loop_id}/generate-plan")
- def generate_loop_plan(loop_id: str):
- """Step 1: Generate simulation plan from natural language.
- Uses Kimi k3 AI model to convert the user requirement into
- a structured simulation plan with scan variables, search strategy,
- and acceptance criteria.
- """
- loop = get_loop(loop_id)
- if not loop:
- raise HTTPException(status_code=404, detail=f"Loop {loop_id} not found")
- try:
- return loop.generate_plan()
- except Exception as e:
- raise HTTPException(status_code=500, detail=f"Plan generation failed: {str(e)}")
- @router.post("/loops/{loop_id}/init-search")
- def init_loop_search(loop_id: str):
- """Step 2-3: Initialize feasibility-first search.
- Converts plan scan variables to search parameters, runs L0
- pre-screening, and generates initial LHS batch.
- """
- loop = get_loop(loop_id)
- if not loop:
- raise HTTPException(status_code=404, detail=f"Loop {loop_id} not found")
- try:
- return loop.initialize_search()
- except Exception as e:
- raise HTTPException(status_code=500, detail=f"Search init failed: {str(e)}")
- @router.post("/loops/{loop_id}/next-batch")
- def get_loop_next_batch(loop_id: str):
- """Step 3 (loop): Select next batch of points to simulate.
- Uses active learning with trust region refinement to balance
- exploration and exploitation.
- """
- loop = get_loop(loop_id)
- if not loop:
- raise HTTPException(status_code=404, detail=f"Loop {loop_id} not found")
- try:
- return loop.get_next_batch()
- except Exception as e:
- raise HTTPException(status_code=500, detail=f"Batch selection failed: {str(e)}")
- @router.post("/loops/{loop_id}/report-results")
- def report_loop_results(loop_id: str, request: ReportResultsRequest):
- """Step 4-5: Report simulation results and trigger AI analysis.
- Reports results for the current batch, updates search state,
- runs AI result analysis with multi-fidelity calibration and
- confidence grading.
- """
- loop = get_loop(loop_id)
- if not loop:
- raise HTTPException(status_code=404, detail=f"Loop {loop_id} not found")
- try:
- return loop.report_results(request.point_results)
- except Exception as e:
- raise HTTPException(status_code=500, detail=f"Result reporting failed: {str(e)}")
- @router.post("/loops/{loop_id}/update-experience")
- def update_loop_experience(loop_id: str):
- """Step 6: Extract AI insights and update experience library.
- Uses AI to extract design rules, failure patterns, and parameter
- sensitivity from accumulated simulation results.
- """
- loop = get_loop(loop_id)
- if not loop:
- raise HTTPException(status_code=404, detail=f"Loop {loop_id} not found")
- try:
- return loop.update_experience()
- except Exception as e:
- raise HTTPException(status_code=500, detail=f"Experience update failed: {str(e)}")
- @router.get("/loops/{loop_id}/check-completion")
- def check_loop_completion(loop_id: str):
- """Check if the adaptive loop should terminate.
- Returns completion status based on convergence and budget.
- """
- loop = get_loop(loop_id)
- if not loop:
- raise HTTPException(status_code=404, detail=f"Loop {loop_id} not found")
- return loop.check_completion()
- @router.get("/phases")
- def get_loop_phases():
- """Get all possible loop phases."""
- return {
- "phases": [
- {"name": p.name, "value": p.value, "description": _phase_description(p)}
- for p in LoopPhase
- ]
- }
- def _phase_description(phase: LoopPhase) -> str:
- """Get human-readable description of a phase."""
- descriptions = {
- LoopPhase.INIT: "Loop initialized, waiting for plan generation",
- LoopPhase.PLAN_GENERATED: "AI plan generated from natural language",
- LoopPhase.L0_SCREENED: "L0 pre-screening completed",
- LoopPhase.SEARCH_INITIALIZED: "Feasibility-first search initialized with LHS batch",
- LoopPhase.BATCH_SELECTED: "Next batch of points selected via active learning",
- LoopPhase.SIMULATION_RUNNING: "Simulation execution in progress",
- LoopPhase.RESULTS_ANALYZED: "AI result analysis completed with confidence grading",
- LoopPhase.EXPERIENCE_UPDATED: "Experience library updated with extracted insights",
- LoopPhase.CONVERGED: "Search converged, loop complete",
- LoopPhase.BUDGET_EXHAUSTED: "Simulation budget exhausted",
- LoopPhase.COMPLETED: "Loop completed successfully",
- }
- return descriptions.get(phase, phase.value)
|