Upload main_py.py
Browse files- main_py.py +67 -0
main_py.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""main.py
|
| 3 |
+
|
| 4 |
+
Automatically generated by Colab.
|
| 5 |
+
|
| 6 |
+
Original file is located at
|
| 7 |
+
https://colab.research.google.com/drive/1dfhQA9-peYN1-9q7ueAUF974jYXx3bKQ
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
from typing import Dict, Any, Optional, List
|
| 11 |
+
from fastapi import FastAPI # FastAPI: lightweight, high-performance web framework
|
| 12 |
+
from pydantic import BaseModel, Field # Pydantic models enforce input/output schemas
|
| 13 |
+
from tools import get_tools # your deterministic toolbelt (modernization, resilience, etc.)
|
| 14 |
+
from agent import ( # agent core: LLM brain, memory, prompt, runner
|
| 15 |
+
create_agent,
|
| 16 |
+
run_infra_resilience_agent,
|
| 17 |
+
ReasoningTrace
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
app = FastAPI( # create the app instance
|
| 21 |
+
title="InfraResilience Agent API", # helpful metadata (shows in /docs)
|
| 22 |
+
version="0.1.0",
|
| 23 |
+
description="Modernization + Resilience planning agent (LangChain + MCP + Tools)."
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
# ---------- Request / Response Schemas (Pydantic) ----------
|
| 27 |
+
class AnalyzeStackRequest(BaseModel):
|
| 28 |
+
"""Input contract for /analyze-stack."""
|
| 29 |
+
legacy_stack: Dict[str, Any] = Field(..., description="Legacy stack as a dict (scheduler, language, architecture, dependencies, etc.)")
|
| 30 |
+
outage_scenario: Optional[str] = Field(None, description="Optional failure scenario to plan resilience tests (e.g., 'Oracle DB down 30 min').")
|
| 31 |
+
|
| 32 |
+
class AnalyzeStackResponse(BaseModel):
|
| 33 |
+
"""Output contract for /analyze-stack."""
|
| 34 |
+
modernization_plan: List[str] # actionable modernization bullets
|
| 35 |
+
resilience_strategy: List[str] # resilience drills/test ideas
|
| 36 |
+
reasoning_summary: str # short, user-facing reasoning summary
|
| 37 |
+
reasoning_trace: List[str] # coarse trace for observability (not raw CoT)
|
| 38 |
+
|
| 39 |
+
# ---------- Single agent instance (cheap + thread-safe for dev) ----------
|
| 40 |
+
TOOLS = get_tools() # build your tool list once at startup
|
| 41 |
+
AGENT = create_agent(TOOLS) # wire LLM + tools + memory (MCP)
|
| 42 |
+
|
| 43 |
+
# ---------- Route: POST /analyze-stack ----------
|
| 44 |
+
@app.post("/analyze-stack", response_model=AnalyzeStackResponse)
|
| 45 |
+
def analyze_stack(payload: AnalyzeStackRequest) -> AnalyzeStackResponse:
|
| 46 |
+
"""
|
| 47 |
+
Accepts a legacy stack + optional outage scenario,
|
| 48 |
+
invokes the agent, and returns modernization + resilience guidance.
|
| 49 |
+
"""
|
| 50 |
+
trace = ReasoningTrace() # lightweight trace for clients (observability)
|
| 51 |
+
trace.add("API request accepted. Dispatching to agent.")
|
| 52 |
+
|
| 53 |
+
result = run_infra_resilience_agent( # call your brain with the structured inputs
|
| 54 |
+
agent_executor=AGENT,
|
| 55 |
+
legacy_stack=payload.legacy_stack,
|
| 56 |
+
outage_scenario=payload.outage_scenario,
|
| 57 |
+
trace=trace,
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
return AnalyzeStackResponse(**result) # pydantic enforces shape/types on the way out
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
# ---------- Optional: simple health endpoint ----------
|
| 64 |
+
@app.get("/healthz")
|
| 65 |
+
def health() -> Dict[str, str]:
|
| 66 |
+
"""K8s/ECS-friendly liveness probe."""
|
| 67 |
+
return {"status": "ok"}
|