from __future__ import annotations from app.agents.schemas.learning import SessionRetrospective from app.agents.skills.matcher import score_text_match from app.agents.learning.store import SessionRetrospectiveStore from app.config import settings class SessionRetrospectiveSearch: def __init__(self, db): self.db = db async def shortlist( self, *, user_id: str, query_text: str, conversation_id: str | None = None, task_type: str | None = None, skill_name: str | None = None, limit: int = 3, ) -> list[SessionRetrospective]: records = await SessionRetrospectiveStore(self.db).list_recent(user_id=user_id, limit=25) scored: list[tuple[float, SessionRetrospective]] = [] for record in records: if task_type and record.task_type != task_type: continue if skill_name and skill_name not in (record.skill_names or []): continue score, _matched_terms = score_text_match( query_text, record.query_text, record.summary_text, " ".join(record.skill_names or []), ) if conversation_id and record.conversation_id == conversation_id: score = min(1.0, score + 0.1) if score <= 0: continue payload = dict(record.payload or {}) payload["retrospective_id"] = record.id retrospective = SessionRetrospective.model_validate(payload) scored.append((score, retrospective)) scored.sort(key=lambda item: item[0], reverse=True) return [item for _score, item in scored[:limit]] async def search_recent_retrospectives( db, *, user_id: str, query: str, conversation_id: str | None = None, task_type: str | None = None, skill_name: str | None = None, limit: int = 3, ) -> list[SessionRetrospective]: if not settings.ENABLE_SESSION_RETROSPECTIVE_SEARCH: return [] return await SessionRetrospectiveSearch(db).shortlist( user_id=user_id, query_text=query, conversation_id=conversation_id, task_type=task_type, skill_name=skill_name, limit=limit, ) def summarize_retrospective(retrospective: SessionRetrospective) -> dict[str, object]: verification_status = retrospective.verification_status or retrospective.outcome success_score = 1.0 if verification_status == "passed" else 0.6 if verification_status == "skipped" else 0.2 reusable_patterns = [] if retrospective.used_skill_names: reusable_patterns.append("skill_shortlist_hit") if retrospective.execution_mode: reusable_patterns.append(f"mode:{retrospective.execution_mode}") avoid_patterns = [] if retrospective.outcome == "failed": avoid_patterns.append("failed_outcome") return { "retrospective_id": retrospective.retrospective_id, "task_type": retrospective.task_type, "request_summary": retrospective.query_text[:120], "summary": retrospective.summary, "execution_mode": retrospective.execution_mode, "success_score": round(success_score, 2), "reusable_patterns": reusable_patterns, "avoid_patterns": avoid_patterns, }