|
3 | 3 | """ |
4 | 4 |
|
5 | 5 | import os |
| 6 | +from contextlib import asynccontextmanager |
6 | 7 | from typing import Optional |
7 | 8 |
|
8 | 9 | import weaviate |
9 | 10 | from fastapi import APIRouter, FastAPI, HTTPException, Request |
| 11 | +from fastapi.middleware.cors import CORSMiddleware |
| 12 | +from starlette.middleware.base import BaseHTTPMiddleware |
10 | 13 | from pydantic import BaseModel |
11 | 14 |
|
12 | 15 | from a2a.routes import router as a2a_router |
13 | | - |
14 | | -# Clean relative imports |
15 | | -from auth import verify_jwt |
16 | 16 | from auth.oidc import _require_env |
17 | | - |
18 | | -# from logs import router as logs_router |
| 17 | +import logs |
| 18 | +logs_router = logs.router |
19 | 19 | from mem import get_memory_backend |
20 | 20 | from middleware.auth import jwt_auth_mw |
21 | | -from middleware.quota import TokenQuotaMiddleware |
22 | 21 | from middleware.session import session_mw |
23 | 22 | from proxy.engine import router as proxy_router |
| 23 | +from usage.factory import _select_backend, get_usage_backend |
| 24 | +from usage.metrics import mount_metrics |
| 25 | +from utils.env import int_env |
| 26 | + |
| 27 | +# Guard TokenQuotaMiddleware import (matches main.py pattern) |
| 28 | +try: |
| 29 | + from middleware.quota import TokenQuotaMiddleware |
| 30 | + QUOTA_AVAILABLE = True |
| 31 | +except ImportError: # optional extra not installed |
| 32 | + QUOTA_AVAILABLE = False |
24 | 33 |
|
25 | 34 | # Import version from parent package |
26 | 35 | from . import __version__ |
@@ -49,7 +58,7 @@ async def get_memory_events(request: Request, limit: int = 10): |
49 | 58 | return {"data": {"Get": {"MemoryEvent": []}}} |
50 | 59 |
|
51 | 60 | result = ( |
52 | | - client.query.get("MemoryEvent", ["timestamp", "role", "content"]) |
| 61 | + client.query.get("MemoryEvent", ["timestamp", "event", "user", "state"]) |
53 | 62 | .with_additional(["id"]) |
54 | 63 | .with_limit(limit) |
55 | 64 | .with_sort([{"path": ["timestamp"], "order": "desc"}]) |
@@ -97,6 +106,21 @@ class AttachConfig(BaseModel): |
97 | 106 | auth0_client: Optional[str] = None |
98 | 107 |
|
99 | 108 |
|
| 109 | +@asynccontextmanager |
| 110 | +async def lifespan(app: FastAPI): |
| 111 | + """Manage application lifespan - startup and shutdown.""" |
| 112 | + # Startup |
| 113 | + backend_selector = _select_backend() |
| 114 | + app.state.usage = get_usage_backend(backend_selector) |
| 115 | + mount_metrics(app) |
| 116 | + |
| 117 | + yield |
| 118 | + |
| 119 | + # Shutdown |
| 120 | + if hasattr(app.state.usage, 'aclose'): |
| 121 | + await app.state.usage.aclose() |
| 122 | + |
| 123 | + |
100 | 124 | def create_app(config: Optional[AttachConfig] = None) -> FastAPI: |
101 | 125 | """ |
102 | 126 | Create a FastAPI app with Attach Gateway functionality |
@@ -127,17 +151,38 @@ def create_app(config: Optional[AttachConfig] = None) -> FastAPI: |
127 | 151 | title="Attach Gateway", |
128 | 152 | description="Identity & Memory side-car for LLM engines", |
129 | 153 | version=__version__, |
| 154 | + lifespan=lifespan, |
| 155 | + ) |
| 156 | + |
| 157 | + @app.get("/auth/config") |
| 158 | + async def auth_config(): |
| 159 | + return { |
| 160 | + "domain": config.auth0_domain, |
| 161 | + "client_id": config.auth0_client, |
| 162 | + "audience": config.oidc_audience, |
| 163 | + } |
| 164 | + |
| 165 | + # Add middleware in correct order (CORS outer-most) |
| 166 | + app.add_middleware( |
| 167 | + CORSMiddleware, |
| 168 | + allow_origins=["http://localhost:9000", "http://127.0.0.1:9000"], |
| 169 | + allow_methods=["*"], |
| 170 | + allow_headers=["*"], |
| 171 | + allow_credentials=True, |
130 | 172 | ) |
| 173 | + |
| 174 | + # Only add quota middleware if available and explicitly configured |
| 175 | + limit = int_env("MAX_TOKENS_PER_MIN", 60000) |
| 176 | + if QUOTA_AVAILABLE and limit is not None: |
| 177 | + app.add_middleware(TokenQuotaMiddleware) |
131 | 178 |
|
132 | | - # Add middleware |
133 | | - app.middleware("http")(jwt_auth_mw) |
134 | | - app.middleware("http")(session_mw) |
135 | | - app.add_middleware(TokenQuotaMiddleware) |
| 179 | + app.add_middleware(BaseHTTPMiddleware, dispatch=jwt_auth_mw) |
| 180 | + app.add_middleware(BaseHTTPMiddleware, dispatch=session_mw) |
136 | 181 |
|
137 | 182 | # Add routes |
138 | | - app.include_router(a2a_router) |
| 183 | + app.include_router(a2a_router, prefix="/a2a") |
139 | 184 | app.include_router(proxy_router) |
140 | | - # app.include_router(logs_router) |
| 185 | + app.include_router(logs_router) |
141 | 186 | app.include_router(mem_router) |
142 | 187 |
|
143 | 188 | # Setup memory backend |
|
0 commit comments