Implement runtime agent loop and container hygiene
This commit is contained in:
72
app/main.py
72
app/main.py
@@ -1,7 +1,8 @@
|
||||
"""FastAPI main application."""
|
||||
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.responses import JSONResponse
|
||||
import asyncio
|
||||
from contextlib import suppress
|
||||
from fastapi import FastAPI, HTTPException, Form
|
||||
from datetime import datetime
|
||||
import logging
|
||||
|
||||
@@ -20,15 +21,37 @@ app = FastAPI(
|
||||
|
||||
# Global orchestrator instance
|
||||
orchestrator: AgentOrchestrator | None = None
|
||||
agent_loop_task: asyncio.Task | None = None
|
||||
|
||||
|
||||
async def agent_loop() -> None:
|
||||
"""Run periodic time-based agent behavior for active sessions."""
|
||||
if not orchestrator:
|
||||
return
|
||||
|
||||
while True:
|
||||
try:
|
||||
results = await orchestrator.tick()
|
||||
if results:
|
||||
logger.info(f"Agent loop actions: {results}")
|
||||
except asyncio.CancelledError:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Agent loop tick failed: {e}")
|
||||
|
||||
await asyncio.sleep(orchestrator.loop_interval_seconds)
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup_event():
|
||||
"""Initialize database and services on startup."""
|
||||
global orchestrator
|
||||
global orchestrator, agent_loop_task
|
||||
try:
|
||||
await init_db()
|
||||
orchestrator = AgentOrchestrator()
|
||||
orchestrator = AgentOrchestrator(
|
||||
loop_interval_seconds=settings.AGENT_LOOP_INTERVAL_SECONDS
|
||||
)
|
||||
agent_loop_task = asyncio.create_task(agent_loop())
|
||||
logger.info("Application started successfully")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to start application: {e}")
|
||||
@@ -38,6 +61,10 @@ async def startup_event():
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown_event():
|
||||
"""Clean up resources on shutdown."""
|
||||
if agent_loop_task:
|
||||
agent_loop_task.cancel()
|
||||
with suppress(asyncio.CancelledError):
|
||||
await agent_loop_task
|
||||
logger.info("Application shutting down")
|
||||
|
||||
|
||||
@@ -53,7 +80,7 @@ async def health_check() -> dict:
|
||||
|
||||
|
||||
@app.post("/admin/session/start")
|
||||
async def start_session(channel_name: str) -> dict:
|
||||
async def start_session(channel_name: str = Form(...)) -> dict:
|
||||
"""Start a new stream session."""
|
||||
if not orchestrator:
|
||||
raise HTTPException(status_code=503, detail="Orchestrator not initialized")
|
||||
@@ -68,7 +95,7 @@ async def start_session(channel_name: str) -> dict:
|
||||
|
||||
|
||||
@app.post("/admin/session/end")
|
||||
async def end_session(session_id: str) -> dict:
|
||||
async def end_session(session_id: str = Form(...)) -> dict:
|
||||
"""End the current stream session."""
|
||||
if not orchestrator:
|
||||
raise HTTPException(status_code=503, detail="Orchestrator not initialized")
|
||||
@@ -82,7 +109,7 @@ async def end_session(session_id: str) -> dict:
|
||||
|
||||
|
||||
@app.post("/admin/test-message")
|
||||
async def test_message(session_id: str, message: str, username: str = "test_user") -> dict:
|
||||
async def test_message(session_id: str = Form(...), message: str = Form(...), username: str = Form("test_user")) -> dict:
|
||||
"""Send a test message to the orchestrator."""
|
||||
if not orchestrator:
|
||||
raise HTTPException(status_code=503, detail="Orchestrator not initialized")
|
||||
@@ -116,6 +143,37 @@ async def get_ledger(session_id: str) -> dict:
|
||||
}
|
||||
|
||||
|
||||
@app.get("/admin/loop/status")
|
||||
async def get_loop_status() -> dict:
|
||||
"""Get the background agent loop runtime configuration."""
|
||||
if not orchestrator:
|
||||
raise HTTPException(status_code=503, detail="Orchestrator not initialized")
|
||||
|
||||
return {
|
||||
"status": "running" if agent_loop_task and not agent_loop_task.done() else "stopped",
|
||||
**orchestrator.get_loop_status(),
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
}
|
||||
|
||||
|
||||
@app.post("/admin/loop/frequency")
|
||||
async def set_loop_frequency(interval_seconds: float = Form(...)) -> dict:
|
||||
"""Set how frequently the background agent loop runs."""
|
||||
if not orchestrator:
|
||||
raise HTTPException(status_code=503, detail="Orchestrator not initialized")
|
||||
|
||||
try:
|
||||
orchestrator.set_loop_interval(interval_seconds)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e)) from e
|
||||
|
||||
return {
|
||||
"status": "loop_frequency_updated",
|
||||
"interval_seconds": orchestrator.loop_interval_seconds,
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(
|
||||
|
||||
Reference in New Issue
Block a user