import json import os from typing import Any, Dict, List from Memory import MemoryManager from Runner import Runner def _env(name: str, default: str) -> str: value = os.getenv(name) if value is None or value.strip() == "": return default return value def _env_int(name: str, default: int) -> int: value = os.getenv(name) if not value: return default try: return max(int(value), 1) except ValueError: return default class AgenticWorkflow: """Builds the hourly context packet and routes it through the agentic prompt.""" @staticmethod def buildReviewPacket(userId: str, noteLimit: int | None = None) -> Dict[str, Any]: limit = noteLimit or _env_int("AGENTIC_NOTES_LIMIT", 5) summaries, notes = MemoryManager.buildContextPacket(userId, noteLimit=limit) action_items = MemoryManager.listActionItems(userId) condensed = [] for action in action_items: entry = { "id": action.get("id"), "title": action.get("title"), "details": action.get("details"), "cadence": action.get("cadence"), "interval_minutes": action.get("interval_minutes"), "updated_at": action.get("updated_at"), "last_progress": (action.get("progress") or [])[-1:] or [], } entry["recent_progress"] = (action.get("progress") or [])[-3:] condensed.append(entry) return { "notes": notes, "summaries": summaries, "action_items": condensed, } @staticmethod def formatPacket(packet: Dict[str, Any], operatorHint: str | None = None) -> str: sections: List[str] = [] sections.append("Agentic sweep payload:") sections.append(json.dumps(packet, indent=2, ensure_ascii=False)) if operatorHint: sections.append(f"Operator hint: {operatorHint}") return "\n\n".join(sections) @staticmethod def runHourlyReview(userId: str, operatorHint: str | None = None, history=None): if not userId: raise ValueError("userId is required for agentic review") packet = AgenticWorkflow.buildReviewPacket(userId) context = AgenticWorkflow.formatPacket(packet, operatorHint) category = _env("AGENTIC_CATEGORY", "agentic") prompt_name = _env("AGENTIC_PROMPT_NAME", "hourly_review") mode_hint = _env("AGENTIC_MODE_HINT", "Agentic review") return Runner.run( userId, category, prompt_name, context, history=history or [], modeHint=mode_hint, )