Spaces:
Runtime error
Runtime error
| """Agent composition root + backwards-compatible facade. | |
| The heavy lifting previously in this file now lives in single-responsibility | |
| services (notification, knowledge, memory, prompt, tools, tenant). This module | |
| only: (1) applies the global IPv4-only DNS patch once, (2) exposes `init_agent` | |
| as the small factory that wires an LLM + bound tools + chat prompt + memory, | |
| and (3) re-exports every public symbol the API, Telegram bot, eval scripts, | |
| and tests still import from `backend.app.core.agent`. | |
| """ | |
| import os | |
| import socket | |
| from typing import Any, Dict, Optional, Tuple | |
| # Force IPv4-only DNS resolution (Hugging Face Spaces / dual-stack hosts can | |
| # stall IPv6 lookups). Applied once at import time, mirroring the legacy boot. | |
| try: | |
| _orig_getaddrinfo = socket.getaddrinfo | |
| def _ipv4_only_getaddrinfo(*args, **kwargs): | |
| res = _orig_getaddrinfo(*args, **kwargs) | |
| ipv4_res = [r for r in res if r[0] == socket.AF_INET] | |
| return ipv4_res or res | |
| socket.getaddrinfo = _ipv4_only_getaddrinfo | |
| except Exception: | |
| pass | |
| from dotenv import load_dotenv | |
| from langchain_openai import ChatOpenAI | |
| from backend.app.services.memory_manager import RollingMemory, MemoryManager | |
| from backend.app.services.prompt_builder import PromptBuilder | |
| from backend.app.services.tool_executor import ( | |
| ToolExecutor, | |
| search_arun_knowledge, | |
| get_github_live_data, | |
| notify_arun, | |
| ) | |
| from backend.app.services.tenant_service import tenant_service, TenantService | |
| from backend.app.services.knowledge_service import knowledge_service | |
| from backend.app.services.notification_service import ( | |
| queue_debug_event, | |
| queue_maybe_notify_arun, | |
| queue_chat_history_to_telegram, | |
| queue_automated_chat_alert, | |
| send_automated_chat_alert, | |
| send_chat_history_to_telegram, | |
| send_debug_event_to_telegram, | |
| schedule_notify_arun, | |
| TELEGRAM_DELIVERY_LOGS, | |
| _deliver_notify_arun, | |
| ) | |
| from backend.app.services.auth_service import generate_admin_token, verify_admin_token | |
| from backend.app.services.agent_runner import AgentRunner, agent_runner, run_pre_escalation | |
| load_dotenv() | |
| __all__ = [ | |
| "init_agent", | |
| "RollingMemory", | |
| "MemoryManager", | |
| "load_static_context", | |
| "load_tutor_config", | |
| "save_unknown_question_answer", | |
| "queue_debug_event", | |
| "queue_maybe_notify_arun", | |
| "run_pre_escalation", | |
| "queue_chat_history_to_telegram", | |
| "queue_automated_chat_alert", | |
| "send_automated_chat_alert", | |
| "send_chat_history_to_telegram", | |
| "send_debug_event_to_telegram", | |
| "schedule_notify_arun", | |
| "generate_admin_token", | |
| "verify_admin_token", | |
| "TELEGRAM_DELIVERY_LOGS", | |
| "search_arun_knowledge", | |
| "get_github_live_data", | |
| "notify_arun", | |
| "ToolExecutor", | |
| "AgentRunner", | |
| "agent_runner", | |
| ] | |
| def init_agent( | |
| temperature: float = 0.4, | |
| model_name: Optional[str] = None, | |
| tutor_id: Optional[str] = None, | |
| ): | |
| """Build a ready-to-run ArunCore agent. | |
| Returns the same 4-tuple as the legacy factory: | |
| (main_llm, chat_prompt, memory, tools). | |
| """ | |
| openai_key = os.getenv("OPENAI_API_KEY") | |
| if not openai_key: | |
| raise ValueError("OPENAI_API_KEY is not set in environment.") | |
| resolved_model = model_name or os.getenv("OPENAI_MODEL", "gpt-4.1-nano") | |
| tools = ToolExecutor.get_enabled_tools(ToolExecutor.DEFAULT_TOOLS) | |
| main_llm = ChatOpenAI( | |
| temperature=temperature, | |
| model=resolved_model, | |
| api_key=openai_key, | |
| ).bind_tools(tools) | |
| system_prompt = PromptBuilder().build_system_prompt(tutor_id=tutor_id) | |
| prompt = PromptBuilder.build_chat_prompt(system_prompt) | |
| summary_llm = ChatOpenAI( | |
| temperature=0.0, | |
| model="gpt-4o-mini", | |
| api_key=openai_key, | |
| ) | |
| memory = RollingMemory(summary_llm=summary_llm) | |
| return main_llm, prompt, memory, tools | |
| def load_tutor_config(tutor_id: Optional[str]) -> Optional[Dict[str, Any]]: | |
| """Legacy demos-dictionary loader (kept for external consumers).""" | |
| return tenant_service.load_legacy_tutor_config(tutor_id) | |
| def save_unknown_question_answer(question: str, answer: str) -> str: | |
| """Persists a verified Q&A pair into the active-learning store.""" | |
| return knowledge_service.save_verified_answer(question, answer) | |
| def load_static_context(): | |
| """Canonical 5-tuple static context reader (system, guardrails, handoff, profile, rules).""" | |
| from backend.app.services.prompt_builder import load_static_context as _load_5 | |
| return _load_5() |