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
- async with httpx.AsyncClient() as client:
759
- response = await client.get(
760
- splash_url,
761
- params={"url": url, "timeout": 12, "wait": 1.0},
762
- timeout=15.0
763
- )
 
764
  if response.status_code == 200:
765
- soup = BeautifulSoup(response.text, 'html.parser')
766
- for script in soup(["script", "style"]):
767
- script.decompose()
768
- text = soup.get_text(separator=' ')
769
- lines = (line.strip() for line in text.splitlines())
770
- chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
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-3.2-11b-vision-preview"
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
- print("NEURAL BOOT: Initializing ChromaDB Memory Vault...")
422
- self._client = chromadb.PersistentClient(path=self.path)
423
- self._collection = self._client.get_or_create_collection(name="aura_memory_vault")
424
- from agent_plugins.rag_advanced import AdvancedRAG
425
- self._rag = AdvancedRAG(self._collection)
 
 
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
- 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).
732
- 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.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
733
 
734
- User Query: "{prompt}"
735
 
736
- Respond with ONLY "SEARCH" or "NO_SEARCH" (nothing else, no explanation, no punctuation)."""
737
-
738
- try:
739
- intent_res = await async_groq_client.chat.completions.create(
740
- model="llama-3.3-70b-versatile",
741
- messages=[{"role": "user", "content": intent_prompt}],
742
- max_tokens=5,
743
- temperature=0.0,
744
- timeout=4.0
745
- )
746
- expanded = intent_res.choices[0].message.content.strip().upper()
747
- if "SEARCH" in expanded and "NO_SEARCH" not in expanded:
748
- is_research_needed = True
749
- print(f"NEURAL INTENT CLASSIFICATION: Detected search requirement.")
750
- else:
751
- print(f"NEURAL INTENT CLASSIFICATION: Query is static.")
752
- except Exception as ex:
753
- print(f"LLM Intent Classification failed, falling back to keywords: {ex}")
754
- # Fallback keyword-based check
755
- is_research_needed = any(k in prompt.lower() for k in [
756
- "score", "news", "today", "weather", "match", "latest",
757
- "who is", "what is", "how is", "price", "stock", "search", "update",
758
- "current", "now", "live", "results", "scheduled", "vs", "who won",
759
- "standing", "points", "ranking", "winner", "tomorrow", "tonight", "happening"
760
- ])
761
- if any(k in prompt.lower() for k in ["how to", "code", "function", "install", "react hooks", "flutter", "python"]):
762
- is_research_needed = False
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(prompt, project_id=project_id)
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
- response_stream = await async_groq_client.chat.completions.create(
1095
- model=map_model_for_backend(chosen_model),
1096
- messages=messages,
1097
- temperature=overlay_params.get("temperature", 0.7),
1098
- max_tokens=overlay_params.get("max_tokens", 2048),
1099
- stream=True
1100
- )
 
 
 
 
 
 
 
 
 
 
1101
 
1102
  async for chunk in response_stream:
1103
- if chunk.choices and chunk.choices[0].delta.content:
1104
- yield ("content", chunk.choices[0].delta.content)
 
 
 
 
 
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(f"User Question in {project_id}: {prompt}")
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(f"Aura Strategic Advice: {full_reply[:500]}...")
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(f"User Question in {project_id}: {prompt}")
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(f"Aura Strategic Advice: {full_reply[:500]}...")
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 = "meta-llama/llama-4-scout-17b-16e-instruct"
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
- max_tokens = min(max_tokens + 120, 550)
 
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.