Initial commit: CI Agent competitive-intelligence monitoring app
FastAPI + Celery + Next.js + Postgres/Redis app with company monitoring, source collection, LLM-based change analysis, enrichment, and account security (Turnstile, escalating lockout, email verification).
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
"""LLM provider interface. Every analysis task (app/prompts/*.py) is written
|
||||
against this Protocol, never against a specific vendor SDK - swapping
|
||||
`LLM_PROVIDER` changes which class `get_llm_provider()` returns and nothing
|
||||
else has to change. `generate_structured` is the primary method: it always
|
||||
returns a validated instance of the caller's Pydantic response model, never
|
||||
raw text, so a malformed model response can never propagate un-typed data
|
||||
into the rest of the app (see `LLMResponseError` / the repair loop in
|
||||
anthropic_provider.py).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Protocol
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class LLMResponseError(Exception):
|
||||
"""Raised when a provider can't produce a response matching the
|
||||
requested schema, even after any repair attempts."""
|
||||
|
||||
|
||||
class LLMProvider(Protocol):
|
||||
provider_name: str
|
||||
|
||||
async def generate_structured[T: BaseModel](
|
||||
self,
|
||||
system_prompt: str,
|
||||
user_prompt: str,
|
||||
response_model: type[T],
|
||||
) -> T: ...
|
||||
|
||||
async def generate_text(self, system_prompt: str, user_prompt: str) -> str: ...
|
||||
Reference in New Issue
Block a user