Spaces:
Runtime error
Runtime error
Upload 41 files
#2
by skandaedutech - opened
- agent_plugins/__pycache__/api_agent.cpython-312.pyc +0 -0
- agent_plugins/__pycache__/search_agent.cpython-312.pyc +0 -0
- agent_plugins/search_agent.py +48 -17
- main.py +126 -50
- overlay_engine.py +3 -2
- response_rules.py +1 -0
agent_plugins/__pycache__/api_agent.cpython-312.pyc
CHANGED
|
Binary files a/agent_plugins/__pycache__/api_agent.cpython-312.pyc and b/agent_plugins/__pycache__/api_agent.cpython-312.pyc differ
|
|
|
agent_plugins/__pycache__/search_agent.cpython-312.pyc
CHANGED
|
Binary files a/agent_plugins/__pycache__/search_agent.cpython-312.pyc and b/agent_plugins/__pycache__/search_agent.cpython-312.pyc differ
|
|
|
agent_plugins/search_agent.py
CHANGED
|
@@ -751,26 +751,57 @@ class ResearchAgent:
|
|
| 751 |
print(f"AOL Async Offload Fail: {e}")
|
| 752 |
return []
|
| 753 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 754 |
async def _scrape_page_with_splash(self, url: str) -> str:
|
| 755 |
-
"""Scrapes the full rendered HTML of a web page using a Splash server (BSD 3-Clause)
|
|
|
|
|
|
|
| 756 |
splash_url = os.getenv("SPLASH_URL", "http://localhost:8050/render.html")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 757 |
try:
|
| 758 |
-
|
| 759 |
-
|
| 760 |
-
|
| 761 |
-
|
| 762 |
-
|
| 763 |
-
|
|
|
|
| 764 |
if response.status_code == 200:
|
| 765 |
-
|
| 766 |
-
|
| 767 |
-
|
| 768 |
-
|
| 769 |
-
|
| 770 |
-
|
| 771 |
-
clean_text = '\n'.join(chunk for chunk in chunks if chunk)
|
| 772 |
-
return clean_text
|
| 773 |
-
except Exception as e:
|
| 774 |
-
print(f"[Splash Scrape Fail] Error crawling {url} via Splash: {e}")
|
| 775 |
return ""
|
| 776 |
|
|
|
|
| 751 |
print(f"AOL Async Offload Fail: {e}")
|
| 752 |
return []
|
| 753 |
|
| 754 |
+
def _clean_html(self, html_content: str) -> str:
|
| 755 |
+
"""Removes script, style, navigation, and other non-content tags from HTML."""
|
| 756 |
+
try:
|
| 757 |
+
soup = BeautifulSoup(html_content, 'html.parser')
|
| 758 |
+
for element in soup(["script", "style", "iframe", "noscript", "header", "footer", "nav"]):
|
| 759 |
+
element.decompose()
|
| 760 |
+
text = soup.get_text(separator=' ')
|
| 761 |
+
lines = (line.strip() for line in text.splitlines())
|
| 762 |
+
chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
|
| 763 |
+
clean_text = '\n'.join(chunk for chunk in chunks if chunk)
|
| 764 |
+
return clean_text
|
| 765 |
+
except Exception:
|
| 766 |
+
return ""
|
| 767 |
+
|
| 768 |
async def _scrape_page_with_splash(self, url: str) -> str:
|
| 769 |
+
"""Scrapes the full rendered HTML of a web page using a Splash server (BSD 3-Clause),
|
| 770 |
+
with an automated direct HTTP client fallback if Splash is offline."""
|
| 771 |
+
splash_enabled = os.getenv("SPLASH_ENABLED", "true").lower() == "true"
|
| 772 |
splash_url = os.getenv("SPLASH_URL", "http://localhost:8050/render.html")
|
| 773 |
+
|
| 774 |
+
# 1. Try Splash Scraper first
|
| 775 |
+
if splash_enabled:
|
| 776 |
+
try:
|
| 777 |
+
async with httpx.AsyncClient() as client:
|
| 778 |
+
response = await client.get(
|
| 779 |
+
splash_url,
|
| 780 |
+
params={"url": url, "timeout": 12, "wait": 1.0},
|
| 781 |
+
timeout=15.0
|
| 782 |
+
)
|
| 783 |
+
if response.status_code == 200:
|
| 784 |
+
clean_content = self._clean_html(response.text)
|
| 785 |
+
if clean_content and len(clean_content.strip()) > 100:
|
| 786 |
+
return clean_content
|
| 787 |
+
except Exception as e:
|
| 788 |
+
print(f"[Splash Scrape Fail] Error crawling {url} via Splash: {e}. Trying direct HTTP fallback...")
|
| 789 |
+
|
| 790 |
+
# 2. Direct HTTP Fallback Scraper (non-JS render)
|
| 791 |
try:
|
| 792 |
+
headers = {
|
| 793 |
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
| 794 |
+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
| 795 |
+
"Accept-Language": "en-US,en;q=0.5"
|
| 796 |
+
}
|
| 797 |
+
async with httpx.AsyncClient(follow_redirects=True) as client:
|
| 798 |
+
response = await client.get(url, headers=headers, timeout=10.0)
|
| 799 |
if response.status_code == 200:
|
| 800 |
+
clean_content = self._clean_html(response.text)
|
| 801 |
+
if clean_content and len(clean_content.strip()) > 100:
|
| 802 |
+
return clean_content
|
| 803 |
+
except Exception as direct_err:
|
| 804 |
+
print(f"[Direct Scrape Fail] Error crawling {url} directly: {direct_err}")
|
| 805 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
| 806 |
return ""
|
| 807 |
|
main.py
CHANGED
|
@@ -114,6 +114,8 @@ class RealtimeIngestionCluster:
|
|
| 114 |
asyncio.create_task(self._ingestion_loop())
|
| 115 |
|
| 116 |
async def _ingestion_loop(self):
|
|
|
|
|
|
|
| 117 |
while self.is_running:
|
| 118 |
try:
|
| 119 |
from agent_plugins.search_agent import ResearchAgent
|
|
@@ -187,6 +189,8 @@ async def startup_event():
|
|
| 187 |
print("NEURAL BOOT: Initializing Memory and Databases...")
|
| 188 |
try:
|
| 189 |
Base.metadata.create_all(bind=engine)
|
|
|
|
|
|
|
| 190 |
print("NEURAL BOOT: Systems Synchronized.")
|
| 191 |
except Exception as e:
|
| 192 |
print(f"BOOT ERROR: {e}")
|
|
@@ -200,6 +204,7 @@ import requests
|
|
| 200 |
|
| 201 |
def map_model_for_backend(model: str) -> str:
|
| 202 |
openrouter_key = os.environ.get("OPENROUTER_API_KEY")
|
|
|
|
| 203 |
if openrouter_key:
|
| 204 |
# OpenRouter Mapping
|
| 205 |
if "llama-3.3-70b" in model or model == "llama-3.3-70b-versatile":
|
|
@@ -208,13 +213,25 @@ def map_model_for_backend(model: str) -> str:
|
|
| 208 |
return "nousresearch/hermes-3-llama-3.1-70b"
|
| 209 |
elif "scout" in model:
|
| 210 |
return model # Let it pass through since meta-llama/llama-4-scout-17b-16e-instruct is valid
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 211 |
elif "vision" in model:
|
| 212 |
return "meta-llama/llama-3.2-11b-vision-instruct"
|
| 213 |
return model
|
| 214 |
else:
|
| 215 |
# GroqCloud Mapping
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
if "scout" in model or "vision" in model:
|
| 217 |
-
return "llama-
|
| 218 |
if "llama-3.1-8b" in model:
|
| 219 |
return "llama-3.1-8b-instant"
|
| 220 |
if "llama-3.3-70b" in model:
|
|
@@ -320,6 +337,7 @@ class AsyncOpenRouterClient:
|
|
| 320 |
if not line:
|
| 321 |
continue
|
| 322 |
if line.startswith("data: "):
|
|
|
|
| 323 |
data_str = line[6:].strip()
|
| 324 |
if data_str == "[DONE]":
|
| 325 |
break
|
|
@@ -354,6 +372,18 @@ else:
|
|
| 354 |
groq_client = GroqClient(api_key=groq_key) if groq_key else None
|
| 355 |
async_groq_client = AsyncGroq(api_key=groq_key) if groq_key else None
|
| 356 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 357 |
def serialize_to_toon(data: Any, indent: int = 0) -> str:
|
| 358 |
"""
|
| 359 |
Serializes standard dictionary/list objects to Token-Oriented Object Notation (TOON) / YAML-like format.
|
|
@@ -414,15 +444,18 @@ class NeuralMemory:
|
|
| 414 |
self._client = None
|
| 415 |
self._collection = None
|
| 416 |
self._rag = None
|
|
|
|
| 417 |
|
| 418 |
@property
|
| 419 |
def client(self):
|
| 420 |
if self._client is None:
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
|
|
|
|
|
|
| 426 |
return self._client
|
| 427 |
|
| 428 |
def retrieve_context(self, query, project_id=None, top_k=3):
|
|
@@ -728,38 +761,54 @@ class InferenceEngine:
|
|
| 728 |
print(f"FORCE SEARCH OVERRIDE: Triggered web search for: '{search_query}'")
|
| 729 |
# Search intent: main chat always eligible; overlay only in research mode
|
| 730 |
elif search_strategy != "local-only" and (not overlay_mode or sandbox.get("assistant_mode") == "research"):
|
| 731 |
-
|
| 732 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 733 |
|
| 734 |
-
User Query: "{prompt}"
|
| 735 |
|
| 736 |
-
Respond with ONLY "SEARCH" or "NO_SEARCH" (nothing else, no explanation, no punctuation)."""
|
| 737 |
-
|
| 738 |
-
|
| 739 |
-
|
| 740 |
-
|
| 741 |
-
|
| 742 |
-
|
| 743 |
-
|
| 744 |
-
|
| 745 |
-
|
| 746 |
-
|
| 747 |
-
|
| 748 |
-
|
| 749 |
-
|
| 750 |
-
|
| 751 |
-
|
| 752 |
-
|
| 753 |
-
|
| 754 |
-
|
| 755 |
-
|
| 756 |
-
|
| 757 |
-
|
| 758 |
-
|
| 759 |
-
|
| 760 |
-
|
| 761 |
-
|
| 762 |
-
|
| 763 |
|
| 764 |
# Conversational Query Expansion if needed
|
| 765 |
if history and is_research_needed:
|
|
@@ -769,6 +818,7 @@ Respond with ONLY "SEARCH" or "NO_SEARCH" (nothing else, no explanation, no punc
|
|
| 769 |
try:
|
| 770 |
chat_history_str = "\n".join([f"{m.get('role', 'user').upper()}: {m.get('content', '')}" for m in filtered_history[-3:]])
|
| 771 |
expansion_prompt = f"""Given the following chat history and a follow-up query, generate an optimized single search query.
|
|
|
|
| 772 |
CHAT HISTORY:
|
| 773 |
{chat_history_str}
|
| 774 |
|
|
@@ -787,8 +837,19 @@ RESPONSE FORMAT: Output ONLY the optimized search query, nothing else. Do NOT in
|
|
| 787 |
print(f"NEURAL INTENT: Query expanded to '{search_query}'")
|
| 788 |
except Exception as ex:
|
| 789 |
print(f"Intent expansion failed: {ex}")
|
|
|
|
| 790 |
else:
|
| 791 |
search_query = prompt
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 792 |
|
| 793 |
research_context = ""
|
| 794 |
if is_research_needed:
|
|
@@ -823,7 +884,7 @@ RESPONSE FORMAT: Output ONLY the optimized search query, nothing else. Do NOT in
|
|
| 823 |
if overlay_mode:
|
| 824 |
memory_context = api_context
|
| 825 |
else:
|
| 826 |
-
memory_context = memory.retrieve_context
|
| 827 |
if api_context and "No matching free APIs" not in api_context:
|
| 828 |
memory_context += "\n\n" + api_context
|
| 829 |
|
|
@@ -1091,17 +1152,32 @@ LIVE DATA RULES:
|
|
| 1091 |
|
| 1092 |
# Start direct streaming of final response
|
| 1093 |
try:
|
| 1094 |
-
|
| 1095 |
-
|
| 1096 |
-
|
| 1097 |
-
|
| 1098 |
-
|
| 1099 |
-
|
| 1100 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1101 |
|
| 1102 |
async for chunk in response_stream:
|
| 1103 |
-
if chunk.choices and chunk.choices
|
| 1104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1105 |
|
| 1106 |
except Exception as e:
|
| 1107 |
cerebras_key = os.environ.get("CEREBRAS_API_KEY")
|
|
@@ -1836,7 +1912,7 @@ async def api_chat_fallback(data: dict):
|
|
| 1836 |
try:
|
| 1837 |
if not incognito:
|
| 1838 |
chat_manager.save_message(user_id, conv_id, project_id, "user", prompt)
|
| 1839 |
-
memory.store_fragment
|
| 1840 |
|
| 1841 |
full_reply = ""
|
| 1842 |
async for chunk_type, content in inference_core.generate_stream(prompt, data.get("history", []), sandbox=sandbox):
|
|
@@ -1846,7 +1922,7 @@ async def api_chat_fallback(data: dict):
|
|
| 1846 |
if not incognito:
|
| 1847 |
chat_manager.save_message(user_id, conv_id, project_id, "assistant", full_reply)
|
| 1848 |
if len(full_reply) > 50:
|
| 1849 |
-
memory.store_fragment
|
| 1850 |
|
| 1851 |
return {"response": strip_robotic_preamble(full_reply)}
|
| 1852 |
except Exception as e:
|
|
@@ -1871,7 +1947,7 @@ async def secured_chat(websocket: WebSocket):
|
|
| 1871 |
|
| 1872 |
if not incognito:
|
| 1873 |
chat_manager.save_message(user_id, conv_id, project_id, "user", prompt)
|
| 1874 |
-
memory.store_fragment
|
| 1875 |
|
| 1876 |
full_reply = ""
|
| 1877 |
accumulated_thought = ""
|
|
@@ -1903,7 +1979,7 @@ async def secured_chat(websocket: WebSocket):
|
|
| 1903 |
if not incognito:
|
| 1904 |
chat_manager.save_message(user_id, conv_id, project_id, "assistant", full_reply, thought=accumulated_thought)
|
| 1905 |
if len(full_reply) > 50:
|
| 1906 |
-
memory.store_fragment
|
| 1907 |
|
| 1908 |
await websocket.send_text(json.dumps({"done": True}))
|
| 1909 |
|
|
|
|
| 114 |
asyncio.create_task(self._ingestion_loop())
|
| 115 |
|
| 116 |
async def _ingestion_loop(self):
|
| 117 |
+
# Allow startup connection without network congestion
|
| 118 |
+
await asyncio.sleep(30)
|
| 119 |
while self.is_running:
|
| 120 |
try:
|
| 121 |
from agent_plugins.search_agent import ResearchAgent
|
|
|
|
| 189 |
print("NEURAL BOOT: Initializing Memory and Databases...")
|
| 190 |
try:
|
| 191 |
Base.metadata.create_all(bind=engine)
|
| 192 |
+
# Pre-load ChromaDB and SentenceTransformer in startup background thread
|
| 193 |
+
_ = memory.client
|
| 194 |
print("NEURAL BOOT: Systems Synchronized.")
|
| 195 |
except Exception as e:
|
| 196 |
print(f"BOOT ERROR: {e}")
|
|
|
|
| 204 |
|
| 205 |
def map_model_for_backend(model: str) -> str:
|
| 206 |
openrouter_key = os.environ.get("OPENROUTER_API_KEY")
|
| 207 |
+
custom_vision_url = os.environ.get("CUSTOM_VISION_API_URL")
|
| 208 |
if openrouter_key:
|
| 209 |
# OpenRouter Mapping
|
| 210 |
if "llama-3.3-70b" in model or model == "llama-3.3-70b-versatile":
|
|
|
|
| 213 |
return "nousresearch/hermes-3-llama-3.1-70b"
|
| 214 |
elif "scout" in model:
|
| 215 |
return model # Let it pass through since meta-llama/llama-4-scout-17b-16e-instruct is valid
|
| 216 |
+
elif "minicpm" in model:
|
| 217 |
+
if custom_vision_url:
|
| 218 |
+
return model # Let it pass through to custom endpoints/OpenRouter
|
| 219 |
+
else:
|
| 220 |
+
# Fallback to a supported high-performance cloud vision model on OpenRouter
|
| 221 |
+
return "google/gemini-3.5-flash"
|
| 222 |
elif "vision" in model:
|
| 223 |
return "meta-llama/llama-3.2-11b-vision-instruct"
|
| 224 |
return model
|
| 225 |
else:
|
| 226 |
# GroqCloud Mapping
|
| 227 |
+
if "minicpm" in model:
|
| 228 |
+
if custom_vision_url:
|
| 229 |
+
return model
|
| 230 |
+
else:
|
| 231 |
+
# Fallback to a supported vision model on Groq
|
| 232 |
+
return "meta-llama/llama-4-scout-17b-16e-instruct"
|
| 233 |
if "scout" in model or "vision" in model:
|
| 234 |
+
return "meta-llama/llama-4-scout-17b-16e-instruct"
|
| 235 |
if "llama-3.1-8b" in model:
|
| 236 |
return "llama-3.1-8b-instant"
|
| 237 |
if "llama-3.3-70b" in model:
|
|
|
|
| 337 |
if not line:
|
| 338 |
continue
|
| 339 |
if line.startswith("data: "):
|
| 340 |
+
print(f"RAW OPENROUTER LINE: {line}")
|
| 341 |
data_str = line[6:].strip()
|
| 342 |
if data_str == "[DONE]":
|
| 343 |
break
|
|
|
|
| 372 |
groq_client = GroqClient(api_key=groq_key) if groq_key else None
|
| 373 |
async_groq_client = AsyncGroq(api_key=groq_key) if groq_key else None
|
| 374 |
|
| 375 |
+
custom_vision_url = os.environ.get("CUSTOM_VISION_API_URL")
|
| 376 |
+
custom_vision_key = os.environ.get("CUSTOM_VISION_API_KEY", "no_key_needed")
|
| 377 |
+
custom_vision_client = None
|
| 378 |
+
|
| 379 |
+
if custom_vision_url:
|
| 380 |
+
print(f"[SYSTEM] AURA local vision router: Active using endpoint {custom_vision_url}")
|
| 381 |
+
from openai import AsyncOpenAI
|
| 382 |
+
custom_vision_client = AsyncOpenAI(
|
| 383 |
+
base_url=custom_vision_url,
|
| 384 |
+
api_key=custom_vision_key
|
| 385 |
+
)
|
| 386 |
+
|
| 387 |
def serialize_to_toon(data: Any, indent: int = 0) -> str:
|
| 388 |
"""
|
| 389 |
Serializes standard dictionary/list objects to Token-Oriented Object Notation (TOON) / YAML-like format.
|
|
|
|
| 444 |
self._client = None
|
| 445 |
self._collection = None
|
| 446 |
self._rag = None
|
| 447 |
+
self._lock = ThreadingLock()
|
| 448 |
|
| 449 |
@property
|
| 450 |
def client(self):
|
| 451 |
if self._client is None:
|
| 452 |
+
with self._lock:
|
| 453 |
+
if self._client is None:
|
| 454 |
+
print("NEURAL BOOT: Initializing ChromaDB Memory Vault...")
|
| 455 |
+
self._client = chromadb.PersistentClient(path=self.path)
|
| 456 |
+
self._collection = self._client.get_or_create_collection(name="aura_memory_vault")
|
| 457 |
+
from agent_plugins.rag_advanced import AdvancedRAG
|
| 458 |
+
self._rag = AdvancedRAG(self._collection)
|
| 459 |
return self._client
|
| 460 |
|
| 461 |
def retrieve_context(self, query, project_id=None, top_k=3):
|
|
|
|
| 761 |
print(f"FORCE SEARCH OVERRIDE: Triggered web search for: '{search_query}'")
|
| 762 |
# Search intent: main chat always eligible; overlay only in research mode
|
| 763 |
elif search_strategy != "local-only" and (not overlay_mode or sandbox.get("assistant_mode") == "research"):
|
| 764 |
+
# Check for temporal keywords override first to prevent LLM classifier from incorrectly skipping
|
| 765 |
+
p_lower = prompt.lower()
|
| 766 |
+
tech_skip = ["python", "javascript", "typescript", "java", "c#", "c++", "rust", "html", "css", "flutter", "dart", "react", "angular", "vue", "docker", "git", "sql", "code", "programming", "array", "object", "string", "loop", "regex"]
|
| 767 |
+
has_tech_skip = any(tk in p_lower for tk in tech_skip)
|
| 768 |
+
|
| 769 |
+
temporal_kws = [
|
| 770 |
+
"current", "latest", "weather", "news", "score", "match", "today", "yesterday", "tomorrow",
|
| 771 |
+
"tonight", "who is", "who won", "ipl", "stock", "price", "update", "now", "live", "results",
|
| 772 |
+
"vs", "standing", "points", "ranking", "winner", "election", "chief minister", "prime minister",
|
| 773 |
+
"president", "cm of", "pm of", "minister of", "cabinet", "governor of", "ceo of"
|
| 774 |
+
]
|
| 775 |
+
|
| 776 |
+
if any(tk in p_lower for tk in temporal_kws) and not has_tech_skip:
|
| 777 |
+
is_research_needed = True
|
| 778 |
+
print(f"TEMPORAL KEYWORD OVERRIDE: Triggered web search for: '{prompt}'")
|
| 779 |
+
else:
|
| 780 |
+
intent_prompt = f"""Identify if the user query requires real-time web search or current/temporal information (e.g., live games, scores, current events, weather, stock prices, recent news, software releases/updates).
|
| 781 |
+
Queries NOT requiring search include general coding questions (e.g., how to use Flutter, explain React hooks, what is Python, how to print in C), general math, creative writing, or basic conversation.
|
| 782 |
|
| 783 |
+
User Query: "{prompt}"
|
| 784 |
|
| 785 |
+
Respond with ONLY "SEARCH" or "NO_SEARCH" (nothing else, no explanation, no punctuation)."""
|
| 786 |
+
|
| 787 |
+
try:
|
| 788 |
+
intent_res = await async_groq_client.chat.completions.create(
|
| 789 |
+
model="llama-3.3-70b-versatile",
|
| 790 |
+
messages=[{"role": "user", "content": intent_prompt}],
|
| 791 |
+
max_tokens=5,
|
| 792 |
+
temperature=0.0,
|
| 793 |
+
timeout=4.0
|
| 794 |
+
)
|
| 795 |
+
expanded = intent_res.choices[0].message.content.strip().upper()
|
| 796 |
+
if "SEARCH" in expanded and "NO_SEARCH" not in expanded:
|
| 797 |
+
is_research_needed = True
|
| 798 |
+
print(f"NEURAL INTENT CLASSIFICATION: Detected search requirement.")
|
| 799 |
+
else:
|
| 800 |
+
print(f"NEURAL INTENT CLASSIFICATION: Query is static.")
|
| 801 |
+
except Exception as ex:
|
| 802 |
+
print(f"LLM Intent Classification failed, falling back to keywords: {ex}")
|
| 803 |
+
# Fallback keyword-based check
|
| 804 |
+
is_research_needed = any(k in prompt.lower() for k in [
|
| 805 |
+
"score", "news", "today", "weather", "match", "latest",
|
| 806 |
+
"who is", "what is", "how is", "price", "stock", "search", "update",
|
| 807 |
+
"current", "now", "live", "results", "scheduled", "vs", "who won",
|
| 808 |
+
"standing", "points", "ranking", "winner", "tomorrow", "tonight", "happening"
|
| 809 |
+
])
|
| 810 |
+
if any(k in prompt.lower() for k in ["how to", "code", "function", "install", "react hooks", "flutter", "python"]):
|
| 811 |
+
is_research_needed = False
|
| 812 |
|
| 813 |
# Conversational Query Expansion if needed
|
| 814 |
if history and is_research_needed:
|
|
|
|
| 818 |
try:
|
| 819 |
chat_history_str = "\n".join([f"{m.get('role', 'user').upper()}: {m.get('content', '')}" for m in filtered_history[-3:]])
|
| 820 |
expansion_prompt = f"""Given the following chat history and a follow-up query, generate an optimized single search query.
|
| 821 |
+
Note: The current year is 2026. If the query asks for temporal or current events, ensure the search query targets 2026 or the present.
|
| 822 |
CHAT HISTORY:
|
| 823 |
{chat_history_str}
|
| 824 |
|
|
|
|
| 837 |
print(f"NEURAL INTENT: Query expanded to '{search_query}'")
|
| 838 |
except Exception as ex:
|
| 839 |
print(f"Intent expansion failed: {ex}")
|
| 840 |
+
search_query = prompt
|
| 841 |
else:
|
| 842 |
search_query = prompt
|
| 843 |
+
else:
|
| 844 |
+
search_query = prompt
|
| 845 |
+
|
| 846 |
+
# Refine search query with current year if it has temporal intent and does not already contain the year
|
| 847 |
+
current_year = "2026"
|
| 848 |
+
temporal_kws = ["current", "latest", "news", "today", "weather", "match", "score", "ipl", "stock", "price", "who is", "who won", "election", "cm", "pm", "president", "now"]
|
| 849 |
+
p_lower = prompt.lower()
|
| 850 |
+
if is_research_needed and any(tk in p_lower for tk in temporal_kws) and current_year not in search_query:
|
| 851 |
+
search_query = f"{search_query} {current_year}"
|
| 852 |
+
print(f"TEMPORAL SEARCH QUERY REFINE: Expanded search query to: '{search_query}'")
|
| 853 |
|
| 854 |
research_context = ""
|
| 855 |
if is_research_needed:
|
|
|
|
| 884 |
if overlay_mode:
|
| 885 |
memory_context = api_context
|
| 886 |
else:
|
| 887 |
+
memory_context = await asyncio.to_thread(memory.retrieve_context, prompt, project_id)
|
| 888 |
if api_context and "No matching free APIs" not in api_context:
|
| 889 |
memory_context += "\n\n" + api_context
|
| 890 |
|
|
|
|
| 1152 |
|
| 1153 |
# Start direct streaming of final response
|
| 1154 |
try:
|
| 1155 |
+
if base64_image_content and custom_vision_client:
|
| 1156 |
+
print(f"CUSTOM VISION ROUTING: Sending screenshot to self-hosted endpoint: {custom_vision_url}")
|
| 1157 |
+
response_stream = await custom_vision_client.chat.completions.create(
|
| 1158 |
+
model=chosen_model,
|
| 1159 |
+
messages=messages,
|
| 1160 |
+
temperature=overlay_params.get("temperature", 0.7),
|
| 1161 |
+
max_tokens=overlay_params.get("max_tokens", 2048),
|
| 1162 |
+
stream=True
|
| 1163 |
+
)
|
| 1164 |
+
else:
|
| 1165 |
+
response_stream = await async_groq_client.chat.completions.create(
|
| 1166 |
+
model=map_model_for_backend(chosen_model),
|
| 1167 |
+
messages=messages,
|
| 1168 |
+
temperature=overlay_params.get("temperature", 0.7),
|
| 1169 |
+
max_tokens=overlay_params.get("max_tokens", 2048),
|
| 1170 |
+
stream=True
|
| 1171 |
+
)
|
| 1172 |
|
| 1173 |
async for chunk in response_stream:
|
| 1174 |
+
if chunk.choices and len(chunk.choices) > 0:
|
| 1175 |
+
delta = chunk.choices[0].delta
|
| 1176 |
+
content = getattr(delta, "content", None)
|
| 1177 |
+
if not content and isinstance(delta, dict):
|
| 1178 |
+
content = delta.get("content")
|
| 1179 |
+
if content:
|
| 1180 |
+
yield ("content", content)
|
| 1181 |
|
| 1182 |
except Exception as e:
|
| 1183 |
cerebras_key = os.environ.get("CEREBRAS_API_KEY")
|
|
|
|
| 1912 |
try:
|
| 1913 |
if not incognito:
|
| 1914 |
chat_manager.save_message(user_id, conv_id, project_id, "user", prompt)
|
| 1915 |
+
asyncio.create_task(asyncio.to_thread(memory.store_fragment, f"User Question in {project_id}: {prompt}", project_id))
|
| 1916 |
|
| 1917 |
full_reply = ""
|
| 1918 |
async for chunk_type, content in inference_core.generate_stream(prompt, data.get("history", []), sandbox=sandbox):
|
|
|
|
| 1922 |
if not incognito:
|
| 1923 |
chat_manager.save_message(user_id, conv_id, project_id, "assistant", full_reply)
|
| 1924 |
if len(full_reply) > 50:
|
| 1925 |
+
asyncio.create_task(asyncio.to_thread(memory.store_fragment, f"Aura Strategic Advice: {full_reply[:500]}...", project_id))
|
| 1926 |
|
| 1927 |
return {"response": strip_robotic_preamble(full_reply)}
|
| 1928 |
except Exception as e:
|
|
|
|
| 1947 |
|
| 1948 |
if not incognito:
|
| 1949 |
chat_manager.save_message(user_id, conv_id, project_id, "user", prompt)
|
| 1950 |
+
asyncio.create_task(asyncio.to_thread(memory.store_fragment, f"User Question in {project_id}: {prompt}", project_id))
|
| 1951 |
|
| 1952 |
full_reply = ""
|
| 1953 |
accumulated_thought = ""
|
|
|
|
| 1979 |
if not incognito:
|
| 1980 |
chat_manager.save_message(user_id, conv_id, project_id, "assistant", full_reply, thought=accumulated_thought)
|
| 1981 |
if len(full_reply) > 50:
|
| 1982 |
+
asyncio.create_task(asyncio.to_thread(memory.store_fragment, f"Aura Strategic Advice: {full_reply[:500]}...", project_id))
|
| 1983 |
|
| 1984 |
await websocket.send_text(json.dumps({"done": True}))
|
| 1985 |
|
overlay_engine.py
CHANGED
|
@@ -18,7 +18,7 @@ OVERLAY_CONVERSATION_ID = "aura_overlay"
|
|
| 18 |
OVERLAY_SLM_MODEL = "llama-3.1-8b-instant"
|
| 19 |
|
| 20 |
# Groq multimodal model (replaces decommissioned llama-3.2-11b-vision-preview)
|
| 21 |
-
GROQ_VISION_MODEL = "
|
| 22 |
GROQ_VISION_MAX_B64_BYTES = 3_500_000 # Groq limit is 4MB for base64 images
|
| 23 |
|
| 24 |
ASSISTANT_MODES = ("quick", "tutor", "copilot", "research", "focus")
|
|
@@ -115,7 +115,8 @@ def get_overlay_inference_params(sandbox: dict, has_screenshot: bool = False) ->
|
|
| 115 |
cfg = MODE_RULES.get(mode, MODE_RULES["copilot"])
|
| 116 |
max_tokens = cfg["max_tokens"]
|
| 117 |
if has_screenshot:
|
| 118 |
-
|
|
|
|
| 119 |
return {
|
| 120 |
"max_tokens": max_tokens,
|
| 121 |
"temperature": cfg["temperature"],
|
|
|
|
| 18 |
OVERLAY_SLM_MODEL = "llama-3.1-8b-instant"
|
| 19 |
|
| 20 |
# Groq multimodal model (replaces decommissioned llama-3.2-11b-vision-preview)
|
| 21 |
+
GROQ_VISION_MODEL = os.environ.get("GROQ_VISION_MODEL", "openbmb/minicpm-v-2.6")
|
| 22 |
GROQ_VISION_MAX_B64_BYTES = 3_500_000 # Groq limit is 4MB for base64 images
|
| 23 |
|
| 24 |
ASSISTANT_MODES = ("quick", "tutor", "copilot", "research", "focus")
|
|
|
|
| 115 |
cfg = MODE_RULES.get(mode, MODE_RULES["copilot"])
|
| 116 |
max_tokens = cfg["max_tokens"]
|
| 117 |
if has_screenshot:
|
| 118 |
+
# Increase token limit significantly to prevent truncation due to reasoning tokens
|
| 119 |
+
max_tokens = max(max_tokens, 2048)
|
| 120 |
return {
|
| 121 |
"max_tokens": max_tokens,
|
| 122 |
"temperature": cfg["temperature"],
|
response_rules.py
CHANGED
|
@@ -11,6 +11,7 @@ When using realtime / live web data:
|
|
| 11 |
- Silently use current date and time internally.
|
| 12 |
- Silently use search results internally.
|
| 13 |
- Answer the user directly in natural, conversational language.
|
|
|
|
| 14 |
|
| 15 |
DO NOT:
|
| 16 |
- Mention the current date or year unless the user explicitly asked for it.
|
|
|
|
| 11 |
- Silently use current date and time internally.
|
| 12 |
- Silently use search results internally.
|
| 13 |
- Answer the user directly in natural, conversational language.
|
| 14 |
+
- CRITICAL: Always prioritize the most recent information (e.g., year 2026 facts over older 2021-2025 facts) provided in the LIVE DATA block. Do not rely on your static knowledge cutoff if it contradicts the live web data.
|
| 15 |
|
| 16 |
DO NOT:
|
| 17 |
- Mention the current date or year unless the user explicitly asked for it.
|