Create Relay Bot MVP

This commit is contained in:
Emil
2026-07-24 22:36:04 +03:00
commit d6dc624301
51 changed files with 2226 additions and 0 deletions
View File
+36
View File
@@ -0,0 +1,36 @@
from app.llm.prompts import CLASSIFIER_PROMPT
from app.llm.schemas import Classification
def _confidence(value: object) -> float:
named_levels = {"high": 0.9, "medium": 0.6, "low": 0.3}
if isinstance(value, str) and value.lower() in named_levels:
return named_levels[value.lower()]
try:
return min(1.0, max(0.0, float(value)))
except (TypeError, ValueError):
return 0.0
def _flag(value: object) -> bool:
if isinstance(value, str):
return value.strip().lower() in {"true", "yes", "1"}
return bool(value)
class MessageClassifier:
def __init__(self, llm):
self.llm = llm
async def classify(self, text: str) -> Classification:
data = await self.llm.json(
[{"role": "user", "content": f"{CLASSIFIER_PROMPT}\nMessage:\n{text}"}]
)
return Classification(
is_question=_flag(data.get("is_question")),
project_related=_flag(data.get("project_related")),
asks_new_decision=_flag(data.get("asks_new_decision")),
rhetorical=_flag(data.get("rhetorical")),
blocker=_flag(data.get("blocker")),
confidence=_confidence(data.get("confidence", 0)),
)
+38
View File
@@ -0,0 +1,38 @@
from dataclasses import dataclass
from hashlib import sha256
from app.llm.schemas import Classification
@dataclass(frozen=True)
class ProactiveDecision:
respond: bool
reason: str
fingerprint: str
def decide(
mode: str,
classification: Classification,
*,
is_mention: bool,
duplicate: bool,
cooldown: bool,
threshold: float,
) -> ProactiveDecision:
fingerprint = sha256(repr(classification).encode()).hexdigest()
if mode == "off":
return ProactiveDecision(False, "mode_off", fingerprint)
if mode == "mentions" and not is_mention:
return ProactiveDecision(False, "not_mentioned", fingerprint)
if duplicate or cooldown:
return ProactiveDecision(False, "anti_spam", fingerprint)
if not classification.is_question or classification.rhetorical:
return ProactiveDecision(False, "not_actionable_question", fingerprint)
if not classification.project_related:
return ProactiveDecision(False, "not_project_related", fingerprint)
if classification.asks_new_decision:
return ProactiveDecision(False, "requires_human_decision", fingerprint)
if classification.confidence < threshold:
return ProactiveDecision(False, "low_confidence", fingerprint)
return ProactiveDecision(True, "confirmed_fact_candidate", fingerprint)