Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pydantic = ">=2.8.0"
pydantic-settings = ">=2.3.4"
python-dotenv = ">=1.0.1"
orjson = ">=3.10.6"
maping-client = ">=0.1.1,<0.2.0"

# Agentic stack
langchain = ">=0.2.14"
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pydantic>=2.8.0
pydantic-settings>=2.3.4
python-dotenv>=1.0.1
orjson>=3.10.6
maping-client>=0.1.1,<0.2.0

# Agentic stack
langchain>=0.2.14
Expand Down
4 changes: 2 additions & 2 deletions scripts/export_openapi.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from __future__ import annotations
import json
from agentic_ai.app import app
from agentic_ai.app import fastapi_app

if __name__ == "__main__":
with open("openapi.json","w",encoding="utf-8") as f:
json.dump(app.openapi(), f, ensure_ascii=False, indent=2)
json.dump(fastapi_app.openapi(), f, ensure_ascii=False, indent=2)
print("openapi.json written")
31 changes: 28 additions & 3 deletions src/agentic_ai/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io
import json
import os
import sys
import uuid
from contextlib import asynccontextmanager
Expand All @@ -10,6 +11,8 @@

from fastapi import Body, FastAPI, HTTPException, Request
from fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse
from maping import Recorder
from maping.asgi import MapingMiddleware
from sse_starlette.sse import EventSourceResponse

from .config import settings
Expand Down Expand Up @@ -37,10 +40,14 @@ def _resolve_static(directory: Path, filename: str) -> Path:
# ---------------------------------------------------------------------------
# Lifespan (replaces deprecated @app.on_event)
# ---------------------------------------------------------------------------
recorder = Recorder(service="agentic_ai_pipeline")


@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application startup / shutdown lifecycle."""
# --- startup ---
await recorder.start()
try:
from .social_media_api import init_social_media_services

Expand All @@ -49,9 +56,15 @@ async def lifespan(app: FastAPI):
except Exception as exc:
logger.warning("Social media services unavailable (non-fatal): %s", exc)
logger.info("Agentic AI server started on %s:%s", settings.APP_HOST, settings.APP_PORT)
yield
# --- shutdown ---
logger.info("Agentic AI server shutting down")
try:
yield
finally:
# --- shutdown ---
# In a finally block so the recorder still flushes its final window and
# closes its transport when teardown arrives as an exception or a
# cancellation, which skips any statement placed after the yield.
await recorder.shutdown()
logger.info("Agentic AI server shutting down")


# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -495,3 +508,15 @@ def api_data_run(payload: dict = Body(...)):
if ev == "report":
final_report = data
return {"report": final_report or "", "ok": True}


# `fastapi_app` always stays the FastAPI instance, so callers needing the
# framework API (`app.openapi()`, route introspection, TestClient internals)
# have a stable symbol regardless of MAPING_KEY. `app` remains the ASGI
# entrypoint every runner already points at, wrapped outermost when monitoring
# is enabled so the middleware sits outside ServerErrorMiddleware and observes
# the real 500 status rather than the exception.
fastapi_app = app

if os.environ.get("MAPING_KEY"):
app = MapingMiddleware(app, recorder=recorder)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Loading