Add rate limiting to /process endpoint

- Uses slowapi for rate limiting
- Default: 10 requests/minute per IP
- Configurable via RATE_LIMIT env var
- Returns HTTP 429 when limit exceeded
This commit is contained in:
egregore 2026-02-02 12:58:33 +00:00
parent 5710c44821
commit ebd78cf88e

22
main.py
View file

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Egregore Brain Service - AI reasoning API Egregore Reason Service - AI reasoning API
Provides HTTP API for conversation processing with Claude. Provides HTTP API for conversation processing with Claude.
Runs on port 8081. Runs on port 8081.
@ -9,9 +9,12 @@ Runs on port 8081.
import os import os
from typing import Optional from typing import Optional
from fastapi import FastAPI, HTTPException from fastapi import FastAPI, HTTPException, Request
from pydantic import BaseModel from pydantic import BaseModel
from dotenv import load_dotenv from dotenv import load_dotenv
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
import anthropic import anthropic
from tools import TOOLS, execute_tool from tools import TOOLS, execute_tool
@ -25,7 +28,15 @@ ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY")
if not ANTHROPIC_API_KEY: if not ANTHROPIC_API_KEY:
raise ValueError("ANTHROPIC_API_KEY not set") raise ValueError("ANTHROPIC_API_KEY not set")
app = FastAPI(title="Egregore Brain Service", docs_url="/docs") # Rate limiting configuration
RATE_LIMIT = os.getenv("RATE_LIMIT", "10/minute")
# Initialize rate limiter
limiter = Limiter(key_func=get_remote_address)
app = FastAPI(title="Egregore Reason Service", docs_url="/docs")
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
# Initialize Anthropic client # Initialize Anthropic client
client = anthropic.AsyncAnthropic(api_key=ANTHROPIC_API_KEY) client = anthropic.AsyncAnthropic(api_key=ANTHROPIC_API_KEY)
@ -45,7 +56,8 @@ class ToolRequest(BaseModel):
# Endpoints # Endpoints
@app.post("/process") @app.post("/process")
async def api_process(req: ProcessRequest): @limiter.limit(RATE_LIMIT)
async def api_process(request: Request, req: ProcessRequest):
"""Process a conversation with tool use loop""" """Process a conversation with tool use loop"""
try: try:
response_blocks = await process_conversation( response_blocks = await process_conversation(
@ -82,7 +94,7 @@ async def api_get_prompt():
@app.get("/health") @app.get("/health")
async def health(): async def health():
"""Health check endpoint""" """Health check endpoint"""
return {"status": "ok", "service": "brain"} return {"status": "ok", "service": "reason"}
if __name__ == "__main__": if __name__ == "__main__":