"""Ask Foresight — the runtime companion. The app must boot and every other screen must keep working when there's no `OPENAI_API_KEY`, so nothing here imports LangChain at module level. `enabled()` is the gate; `run_turn` is imported inside it. """ from __future__ import annotations import os from . import threads __all__ = ["enabled", "model_name", "run_turn", "threads", "describe", "greeting", "SUGGESTED_PROMPTS"] DEFAULT_MODEL = "gpt-5.6-sol" # Served to the client by /api/chat/config so the greeting and starter prompts can # be tuned without a frontend deploy. GREETING = ("Hi {first} — ask me anything about Vanderbilt. I'll look it up in real " "campus information and show you where the answer came from.") GREETING_ANONYMOUS = ("Ask me anything about Vanderbilt. I'll look it up in real " "campus information and show you where the answer came from.") SUGGESTED_PROMPTS = [ {"label": "Find me a club for what I'm into", "domain": "crew"}, {"label": "What does add/drop actually mean?", "domain": "vu"}, {"label": "How do I find summer research?", "domain": "future"}, {"label": "I feel behind everyone else.", "domain": "strengths"}, ] def greeting(first_name: str = "") -> str: return GREETING.format(first=first_name) if first_name else GREETING_ANONYMOUS def model_name() -> str: return os.environ.get("FORESIGHT_CHAT_MODEL", DEFAULT_MODEL) def enabled() -> bool: """Whether the companion can actually answer. False means no API key is configured. The UI reads this and says so honestly rather than letting a student type into a box that will error. """ return bool(os.environ.get("OPENAI_API_KEY")) def run_turn(*args, **kwargs): from .graph import run_turn as _run_turn return _run_turn(*args, **kwargs) def describe() -> dict: return {"enabled": enabled(), "model": model_name() if enabled() else None}