"""Steward application entry point.""" import logging import sys from apscheduler.schedulers.asyncio import AsyncIOScheduler from steward.bot.telegram import build_application, send_proposal from steward.config import get_settings from steward.llm.client import LLMClient from steward.memory.thread_store import ThreadMemoryStore from steward.proposals.generator import ProposalGenerator from steward.tools.client import ToolClient logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s", ) logger = logging.getLogger(__name__) async def _run_scheduled_analysis( generator: ProposalGenerator, app, # type: ignore[type-arg] user_ids: list[int], ) -> None: """Scheduled job: run analysis and push proposal via Telegram.""" logger.info("Running scheduled analysis") proposal = await generator.run() if proposal: await send_proposal(app, proposal, user_ids) else: logger.info("No proposal generated (generator returned None)") def main() -> None: """Start Steward.""" settings = get_settings() if not settings.telegram_bot_token: logger.error("TELEGRAM_BOT_TOKEN is not set – cannot start") sys.exit(1) if not settings.openai_api_key: logger.error("OPENAI_API_KEY is not set – cannot start") sys.exit(1) llm = LLMClient(settings) thread_store = ThreadMemoryStore(settings.thread_memory_path) tool_client: ToolClient | None = None if settings.mcp_server_url: tool_client = ToolClient( base_url=settings.mcp_server_url, api_key=settings.mcp_server_api_key, ) logger.info("MCP tool server configured: %s", settings.mcp_server_url) else: logger.info("No MCP_SERVER_URL configured – tool calling disabled") app = build_application(settings, llm, thread_store, tool_client) generator = ProposalGenerator(settings, llm) scheduler = AsyncIOScheduler() scheduler.add_job( _run_scheduled_analysis, "cron", hour=settings.analysis_cron_hour, minute=settings.analysis_cron_minute, args=[generator, app, settings.telegram_allowed_user_ids], ) scheduler.start() logger.info( "Steward starting: model=%s analysis_url=%s tools=%s", settings.openai_model, settings.analysis_target_url or "(none)", settings.mcp_server_url or "(none)", ) app.run_polling(allowed_updates=["message"]) if __name__ == "__main__": main()