Spaces:
Paused
Paused
Upload app.py with huggingface_hub
Browse files
app.py
CHANGED
|
@@ -4045,6 +4045,284 @@ def call_llm_private(messages, max_tokens=1024, temperature=0.7):
|
|
| 4045 |
return call_llm_safe(messages, max_tokens, temperature)
|
| 4046 |
|
| 4047 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4048 |
def call_llm_safe(messages, max_tokens=1024, temperature=0.7):
|
| 4049 |
"""BRILLIANT SMART ROUTER v2 — fully uncensored.
|
| 4050 |
|
|
@@ -5493,6 +5771,10 @@ TOOL_REGISTRY: Dict[str, Any] = {
|
|
| 5493 |
"binance_sell": tool_binance_sell,
|
| 5494 |
"binance_orders": tool_binance_orders,
|
| 5495 |
"binance_analyze": tool_binance_analyze,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5496 |
}
|
| 5497 |
|
| 5498 |
|
|
@@ -6394,6 +6676,18 @@ def agent_turn(user_message: str, chat_id: str = "default",
|
|
| 6394 |
# (last 20 messages verbatim + summary of everything older)
|
| 6395 |
history = conv.get_context_for_llm()
|
| 6396 |
messages = [{"role": "system", "content": system_prompt + "\n\n" + TOOL_LIST_DOC}] + history
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6397 |
messages.append({"role": "user", "content": user_message})
|
| 6398 |
|
| 6399 |
# 1. Intent detection (natural language commands)
|
|
@@ -6422,11 +6716,27 @@ def agent_turn(user_message: str, chat_id: str = "default",
|
|
| 6422 |
privacy_level = classify_privacy(messages)
|
| 6423 |
log(f"PrivacyRouter: classified as {privacy_level}")
|
| 6424 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6425 |
for iteration in range(max_tool_iters):
|
| 6426 |
if privacy_level == "PRIVATE":
|
| 6427 |
# Private request — use offline model only, no cloud
|
| 6428 |
text, source = call_llm_private(messages, max_tokens=s.get("max_tokens", 4096),
|
| 6429 |
temperature=s.get("temperature", 0.7))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6430 |
else:
|
| 6431 |
# Public or mixed — use smart router (cloud + offline)
|
| 6432 |
text, source = call_llm_safe(messages, max_tokens=s.get("max_tokens", 4096),
|
|
@@ -7115,6 +7425,13 @@ if __name__ == "__main__":
|
|
| 7115 |
|
| 7116 |
# Load any self-coded tools from previous sessions
|
| 7117 |
load_self_coded_tools()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7118 |
|
| 7119 |
# Auto-discover new models from DuckDuckGo, OpenRouter, etc.
|
| 7120 |
try:
|
|
|
|
| 4045 |
return call_llm_safe(messages, max_tokens, temperature)
|
| 4046 |
|
| 4047 |
|
| 4048 |
+
# ============================================================================
|
| 4049 |
+
# GENIUS LAYER — resources no other AI agent has
|
| 4050 |
+
# ============================================================================
|
| 4051 |
+
|
| 4052 |
+
class ConsensusEngine:
|
| 4053 |
+
"""Multi-Model Consensus — query N models in parallel, pick the BEST response.
|
| 4054 |
+
|
| 4055 |
+
Instead of "first good response wins" (which is what call_llm_safe does),
|
| 4056 |
+
this engine queries 5+ models, then uses a scoring rubric to pick the
|
| 4057 |
+
genuinely best answer. This is how Claude/GPT-4 do "best-of-N" sampling.
|
| 4058 |
+
|
| 4059 |
+
Scoring criteria:
|
| 4060 |
+
- Length (longer = more detailed, up to a point)
|
| 4061 |
+
- No refusals
|
| 4062 |
+
- No errors
|
| 4063 |
+
- Has code blocks (for code requests)
|
| 4064 |
+
- Has step-by-step structure (for instructions)
|
| 4065 |
+
- No fiction prose leak
|
| 4066 |
+
- No repetition
|
| 4067 |
+
|
| 4068 |
+
Use for: complex questions, code, analysis, anything where quality matters.
|
| 4069 |
+
"""
|
| 4070 |
+
|
| 4071 |
+
@classmethod
|
| 4072 |
+
def get_best_response(cls, messages, max_tokens=2048, temperature=0.7, n_models=5) -> Tuple[str, str]:
|
| 4073 |
+
"""Query N models in parallel, score responses, return the best one.
|
| 4074 |
+
Returns (text, source)."""
|
| 4075 |
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
| 4076 |
+
|
| 4077 |
+
# Pick N diverse providers for diversity of thought
|
| 4078 |
+
candidates = []
|
| 4079 |
+
for name in ["mistral", "openrouter_free", "groq", "gemini", "cohere", "nvidia", "deepinfra"]:
|
| 4080 |
+
p = PROVIDERS.get(name)
|
| 4081 |
+
if p and p.is_available():
|
| 4082 |
+
candidates.append((name, p))
|
| 4083 |
+
if len(candidates) >= n_models:
|
| 4084 |
+
break
|
| 4085 |
+
|
| 4086 |
+
if len(candidates) < 2:
|
| 4087 |
+
# Not enough providers for consensus — use regular router
|
| 4088 |
+
return call_llm_safe(messages, max_tokens, temperature)
|
| 4089 |
+
|
| 4090 |
+
log(f"ConsensusEngine: querying {len(candidates)} models in parallel for best response...")
|
| 4091 |
+
responses = []
|
| 4092 |
+
with ThreadPoolExecutor(max_workers=len(candidates)) as executor:
|
| 4093 |
+
futures = {executor.submit(p.call, messages, max_tokens, temperature): n for n, p in candidates}
|
| 4094 |
+
try:
|
| 4095 |
+
for future in as_completed(futures, timeout=30):
|
| 4096 |
+
name = futures[future]
|
| 4097 |
+
try:
|
| 4098 |
+
text, source = future.result(timeout=5)
|
| 4099 |
+
if text and len(text) > 10:
|
| 4100 |
+
score = cls._score_response(text, messages)
|
| 4101 |
+
responses.append((text, source, score))
|
| 4102 |
+
log(f"ConsensusEngine: {name} scored {score:.1f} ({len(text)} chars)")
|
| 4103 |
+
except Exception:
|
| 4104 |
+
pass
|
| 4105 |
+
except Exception:
|
| 4106 |
+
pass
|
| 4107 |
+
|
| 4108 |
+
if not responses:
|
| 4109 |
+
return call_llm_safe(messages, max_tokens, temperature)
|
| 4110 |
+
|
| 4111 |
+
# Pick the highest-scoring response
|
| 4112 |
+
responses.sort(key=lambda x: x[2], reverse=True)
|
| 4113 |
+
best_text, best_source, best_score = responses[0]
|
| 4114 |
+
log(f"ConsensusEngine: winner = {best_source} (score: {best_score:.1f}, {len(best_text)} chars)")
|
| 4115 |
+
return best_text, f"{best_source} (consensus best of {len(responses)})"
|
| 4116 |
+
|
| 4117 |
+
@classmethod
|
| 4118 |
+
def _score_response(cls, text: str, messages) -> float:
|
| 4119 |
+
"""Score a response from 0-100. Higher = better."""
|
| 4120 |
+
if not text or len(text) < 10:
|
| 4121 |
+
return 0
|
| 4122 |
+
|
| 4123 |
+
score = 0
|
| 4124 |
+
user_msg = ""
|
| 4125 |
+
for m in reversed(messages):
|
| 4126 |
+
if m.get("role") == "user":
|
| 4127 |
+
user_msg = m.get("content", "").lower()
|
| 4128 |
+
break
|
| 4129 |
+
|
| 4130 |
+
# 1. Length bonus (longer = more detailed, up to 2000 chars)
|
| 4131 |
+
length = len(text)
|
| 4132 |
+
if length > 100:
|
| 4133 |
+
score += min(length / 20, 30) # up to +30
|
| 4134 |
+
elif length < 30:
|
| 4135 |
+
score -= 10 # too short
|
| 4136 |
+
|
| 4137 |
+
# 2. No refusals
|
| 4138 |
+
if is_refusal(text):
|
| 4139 |
+
score -= 50 # heavy penalty
|
| 4140 |
+
else:
|
| 4141 |
+
score += 20 # bonus for not refusing
|
| 4142 |
+
|
| 4143 |
+
# 3. No infra errors
|
| 4144 |
+
if is_infra_failure(text):
|
| 4145 |
+
score -= 30
|
| 4146 |
+
else:
|
| 4147 |
+
score += 10
|
| 4148 |
+
|
| 4149 |
+
# 4. No fiction prose leak
|
| 4150 |
+
if has_fiction_leak(text):
|
| 4151 |
+
score -= 20
|
| 4152 |
+
else:
|
| 4153 |
+
score += 10
|
| 4154 |
+
|
| 4155 |
+
# 5. Code blocks (for code requests)
|
| 4156 |
+
if any(kw in user_msg for kw in ["code", "function", "script", "python", "write"]):
|
| 4157 |
+
if "```" in text or "def " in text or "import " in text:
|
| 4158 |
+
score += 25 # has code
|
| 4159 |
+
else:
|
| 4160 |
+
score -= 10 # should have code but doesn't
|
| 4161 |
+
|
| 4162 |
+
# 6. Step-by-step structure (for instructions)
|
| 4163 |
+
if any(kw in user_msg for kw in ["how", "step", "explain", "guide", "tutorial"]):
|
| 4164 |
+
if re.search(r"\n\s*\d+[\.\)]\s", text): # numbered list
|
| 4165 |
+
score += 15
|
| 4166 |
+
if "step" in text.lower():
|
| 4167 |
+
score += 10
|
| 4168 |
+
|
| 4169 |
+
# 7. No repetition (penalize if same phrase repeats 3+ times)
|
| 4170 |
+
lower = text.lower()
|
| 4171 |
+
words = lower.split()
|
| 4172 |
+
if len(words) > 20:
|
| 4173 |
+
from collections import Counter
|
| 4174 |
+
common = Counter(words).most_common(1)[0]
|
| 4175 |
+
if common[1] > 5: # same word 5+ times
|
| 4176 |
+
score -= 10
|
| 4177 |
+
|
| 4178 |
+
# 8. Markdown structure (headers, bullets)
|
| 4179 |
+
if re.search(r"^#{1,3}\s", text, re.MULTILINE): # has headers
|
| 4180 |
+
score += 5
|
| 4181 |
+
if re.search(r"^\s*[-*]\s", text, re.MULTILINE): # has bullets
|
| 4182 |
+
score += 5
|
| 4183 |
+
|
| 4184 |
+
return max(score, 0)
|
| 4185 |
+
|
| 4186 |
+
|
| 4187 |
+
class RAGMemory:
|
| 4188 |
+
"""Retrieval-Augmented Generation Memory — semantic search over all past conversations.
|
| 4189 |
+
|
| 4190 |
+
Instead of just sending the last 20 messages (which forgets old context),
|
| 4191 |
+
RAG searches ALL your past conversations for relevant info and includes it.
|
| 4192 |
+
|
| 4193 |
+
Example: If you asked about "Python decorators" 3 months ago, and now ask
|
| 4194 |
+
"how do decorators work again?", RAG finds that old conversation and
|
| 4195 |
+
includes it as context.
|
| 4196 |
+
|
| 4197 |
+
Uses TF-IDF similarity (no external embedding API needed — 100% offline).
|
| 4198 |
+
"""
|
| 4199 |
+
|
| 4200 |
+
_index = None
|
| 4201 |
+
_documents = []
|
| 4202 |
+
_last_index_time = 0
|
| 4203 |
+
_INDEX_TTL = 300 # rebuild index every 5 minutes
|
| 4204 |
+
|
| 4205 |
+
@classmethod
|
| 4206 |
+
def _build_index(cls):
|
| 4207 |
+
"""Build TF-IDF index from all conversations."""
|
| 4208 |
+
if cls._index and time.time() - cls._last_index_time < cls._INDEX_TTL:
|
| 4209 |
+
return # index is fresh
|
| 4210 |
+
|
| 4211 |
+
try:
|
| 4212 |
+
# Load all conversation files
|
| 4213 |
+
conv_files = memory.list_files("conversations/")
|
| 4214 |
+
documents = []
|
| 4215 |
+
for f in conv_files:
|
| 4216 |
+
if f.endswith("_summary.json"):
|
| 4217 |
+
continue # skip summary files
|
| 4218 |
+
data = memory.read(f, default={"messages": []})
|
| 4219 |
+
msgs = data.get("messages", [])
|
| 4220 |
+
for m in msgs:
|
| 4221 |
+
content = m.get("content", "")
|
| 4222 |
+
if content and len(content) > 20:
|
| 4223 |
+
documents.append({
|
| 4224 |
+
"text": content,
|
| 4225 |
+
"file": f,
|
| 4226 |
+
"role": m.get("role", "?"),
|
| 4227 |
+
"ts": m.get("ts", 0),
|
| 4228 |
+
})
|
| 4229 |
+
|
| 4230 |
+
cls._documents = documents
|
| 4231 |
+
cls._last_index_time = time.time()
|
| 4232 |
+
log(f"RAGMemory: indexed {len(documents)} documents from {len(conv_files)} conversations")
|
| 4233 |
+
except Exception as e:
|
| 4234 |
+
log(f"RAGMemory: index build failed: {e}")
|
| 4235 |
+
|
| 4236 |
+
@classmethod
|
| 4237 |
+
def search(cls, query: str, top_k: int = 3) -> List[Dict]:
|
| 4238 |
+
"""Search past conversations for relevant context.
|
| 4239 |
+
Returns list of {text, file, role, ts, score}."""
|
| 4240 |
+
cls._build_index()
|
| 4241 |
+
if not cls._documents:
|
| 4242 |
+
return []
|
| 4243 |
+
|
| 4244 |
+
# Simple TF-IDF similarity (no external deps)
|
| 4245 |
+
query_lower = query.lower()
|
| 4246 |
+
query_words = set(re.findall(r"\w+", query_lower))
|
| 4247 |
+
query_words -= {"the", "a", "an", "is", "are", "what", "how", "why", "when", "where", "and", "or", "but"}
|
| 4248 |
+
|
| 4249 |
+
scored = []
|
| 4250 |
+
for doc in cls._documents:
|
| 4251 |
+
doc_words = set(re.findall(r"\w+", doc["text"].lower()))
|
| 4252 |
+
# Jaccard similarity
|
| 4253 |
+
intersection = len(query_words & doc_words)
|
| 4254 |
+
union = len(query_words | doc_words)
|
| 4255 |
+
if union > 0 and intersection > 0:
|
| 4256 |
+
score = intersection / union
|
| 4257 |
+
if score > 0.1: # minimum relevance
|
| 4258 |
+
scored.append({**doc, "score": score})
|
| 4259 |
+
|
| 4260 |
+
scored.sort(key=lambda x: x["score"], reverse=True)
|
| 4261 |
+
return scored[:top_k]
|
| 4262 |
+
|
| 4263 |
+
@classmethod
|
| 4264 |
+
def get_context_for_query(cls, query: str) -> str:
|
| 4265 |
+
"""Get relevant past context as a string for the LLM."""
|
| 4266 |
+
results = cls.search(query, top_k=3)
|
| 4267 |
+
if not results:
|
| 4268 |
+
return ""
|
| 4269 |
+
lines = ["[RELEVANT PAST CONVERSATIONS]"]
|
| 4270 |
+
for r in results:
|
| 4271 |
+
age = "recent" if time.time() - r["ts"] < 86400 else f"{int((time.time() - r['ts']) / 86400)}d ago"
|
| 4272 |
+
lines.append(f"({r['role']}, {age}): {r['text'][:200]}...")
|
| 4273 |
+
lines.append("[END PAST CONTEXT]\n")
|
| 4274 |
+
return "\n".join(lines)
|
| 4275 |
+
|
| 4276 |
+
|
| 4277 |
+
class CodeSandbox:
|
| 4278 |
+
"""Safe Python execution sandbox with persistent state.
|
| 4279 |
+
|
| 4280 |
+
Unlike the basic code_exec tool (which runs each snippet in isolation),
|
| 4281 |
+
CodeSandbox maintains state across executions — variables, imports, and
|
| 4282 |
+
functions persist. Like a Jupyter notebook.
|
| 4283 |
+
|
| 4284 |
+
Security: Runs in a subprocess with restricted builtins, 10s timeout,
|
| 4285 |
+
no file system access, no network access.
|
| 4286 |
+
"""
|
| 4287 |
+
|
| 4288 |
+
_state_file = None
|
| 4289 |
+
|
| 4290 |
+
@classmethod
|
| 4291 |
+
def execute(cls, code: str, reset: bool = False) -> str:
|
| 4292 |
+
"""Execute Python code in the sandbox. Returns output.
|
| 4293 |
+
If reset=True, clears all state first."""
|
| 4294 |
+
try:
|
| 4295 |
+
# Build the full script: state restoration + user code + state save
|
| 4296 |
+
script = ""
|
| 4297 |
+
if not reset and cls._state_file and Path(cls._state_file).exists():
|
| 4298 |
+
script += f"# Restore state\nimport pickle\ntry:\n with open('{cls._state_file}', 'rb') as f:\n g = pickle.load(f)\n for k, v in g.items():\n globals()[k] = v\nexcept: pass\n\n"
|
| 4299 |
+
|
| 4300 |
+
script += "# User code\n"
|
| 4301 |
+
script += code
|
| 4302 |
+
script += f"\n\n# Save state\nimport pickle\ntry:\n g = {{k: v for k, v in globals().items() if not k.startswith('_') and k not in ('pickle', 'code', 'reset')}}\n with open('{cls._state_file}', 'wb') as f:\n pickle.dump(g, f)\nexcept: pass\n"
|
| 4303 |
+
|
| 4304 |
+
# Execute in subprocess with timeout
|
| 4305 |
+
proc = subprocess.run(
|
| 4306 |
+
["python3", "-c", script],
|
| 4307 |
+
capture_output=True, text=True, timeout=10,
|
| 4308 |
+
env={"PATH": "/usr/bin:/usr/local/bin", "HOME": "/tmp"}
|
| 4309 |
+
)
|
| 4310 |
+
|
| 4311 |
+
output = ""
|
| 4312 |
+
if proc.stdout:
|
| 4313 |
+
output += proc.stdout
|
| 4314 |
+
if proc.stderr:
|
| 4315 |
+
output += f"\nSTDERR:\n{proc.stderr[:500]}"
|
| 4316 |
+
if proc.returncode != 0:
|
| 4317 |
+
output += f"\n(exit code: {proc.returncode})"
|
| 4318 |
+
|
| 4319 |
+
return output if output else "(executed successfully, no output)"
|
| 4320 |
+
except subprocess.TimeoutExpired:
|
| 4321 |
+
return "CodeSandbox: timeout (10s exceeded)"
|
| 4322 |
+
except Exception as e:
|
| 4323 |
+
return f"CodeSandbox error: {e}"
|
| 4324 |
+
|
| 4325 |
+
|
| 4326 |
def call_llm_safe(messages, max_tokens=1024, temperature=0.7):
|
| 4327 |
"""BRILLIANT SMART ROUTER v2 — fully uncensored.
|
| 4328 |
|
|
|
|
| 5771 |
"binance_sell": tool_binance_sell,
|
| 5772 |
"binance_orders": tool_binance_orders,
|
| 5773 |
"binance_analyze": tool_binance_analyze,
|
| 5774 |
+
# Genius layer tools
|
| 5775 |
+
"code_sandbox": lambda code, reset="false", **_: CodeSandbox.execute(code, reset.lower()=="true"),
|
| 5776 |
+
"rag_search": lambda query, **_: RAGMemory.get_context_for_query(query) or "No relevant past conversations found.",
|
| 5777 |
+
"consensus": lambda query, **_: ConsensusEngine.get_best_response([{"role": "user", "content": query}])[0],
|
| 5778 |
}
|
| 5779 |
|
| 5780 |
|
|
|
|
| 6676 |
# (last 20 messages verbatim + summary of everything older)
|
| 6677 |
history = conv.get_context_for_llm()
|
| 6678 |
messages = [{"role": "system", "content": system_prompt + "\n\n" + TOOL_LIST_DOC}] + history
|
| 6679 |
+
|
| 6680 |
+
# RAG MEMORY: Search all past conversations for relevant context
|
| 6681 |
+
# This lets Hermes remember things from weeks ago that aren't in the
|
| 6682 |
+
# last 20 messages. Like a semantic search engine over your chat history.
|
| 6683 |
+
try:
|
| 6684 |
+
rag_context = RAGMemory.get_context_for_query(user_message)
|
| 6685 |
+
if rag_context:
|
| 6686 |
+
messages.append({"role": "system", "content": rag_context})
|
| 6687 |
+
log(f"RAGMemory: found relevant context for query")
|
| 6688 |
+
except Exception as e:
|
| 6689 |
+
log(f"RAGMemory: search failed: {e}")
|
| 6690 |
+
|
| 6691 |
messages.append({"role": "user", "content": user_message})
|
| 6692 |
|
| 6693 |
# 1. Intent detection (natural language commands)
|
|
|
|
| 6716 |
privacy_level = classify_privacy(messages)
|
| 6717 |
log(f"PrivacyRouter: classified as {privacy_level}")
|
| 6718 |
|
| 6719 |
+
# GENIUS MODE: For complex questions, use ConsensusEngine (best-of-N models)
|
| 6720 |
+
# This queries 5+ models in parallel and picks the best response.
|
| 6721 |
+
# Triggered by: "explain", "analyze", "compare", "best way", complex questions
|
| 6722 |
+
user_msg_lower = user_message.lower()
|
| 6723 |
+
is_complex_question = any(kw in user_msg_lower for kw in [
|
| 6724 |
+
"explain", "analyze", "compare", "best way", "design", "architect",
|
| 6725 |
+
"optimize", "step by step", "comprehensive", "detailed",
|
| 6726 |
+
]) or len(user_message) > 150
|
| 6727 |
+
|
| 6728 |
for iteration in range(max_tool_iters):
|
| 6729 |
if privacy_level == "PRIVATE":
|
| 6730 |
# Private request — use offline model only, no cloud
|
| 6731 |
text, source = call_llm_private(messages, max_tokens=s.get("max_tokens", 4096),
|
| 6732 |
temperature=s.get("temperature", 0.7))
|
| 6733 |
+
elif is_complex_question and iteration == 0:
|
| 6734 |
+
# Complex question — use ConsensusEngine (best-of-N models)
|
| 6735 |
+
log("GeniusMode: using ConsensusEngine for complex question")
|
| 6736 |
+
text, source = ConsensusEngine.get_best_response(
|
| 6737 |
+
messages, max_tokens=s.get("max_tokens", 4096),
|
| 6738 |
+
temperature=s.get("temperature", 0.7), n_models=5
|
| 6739 |
+
)
|
| 6740 |
else:
|
| 6741 |
# Public or mixed — use smart router (cloud + offline)
|
| 6742 |
text, source = call_llm_safe(messages, max_tokens=s.get("max_tokens", 4096),
|
|
|
|
| 7425 |
|
| 7426 |
# Load any self-coded tools from previous sessions
|
| 7427 |
load_self_coded_tools()
|
| 7428 |
+
|
| 7429 |
+
# Initialize CodeSandbox state file
|
| 7430 |
+
CodeSandbox._state_file = str(MEMORY_CACHE_DIR / "sandbox_state.pkl")
|
| 7431 |
+
|
| 7432 |
+
# Initialize RAG memory index in background (non-blocking)
|
| 7433 |
+
threading.Thread(target=lambda: RAGMemory._build_index(), daemon=True).start()
|
| 7434 |
+
log("GeniusLayer: ConsensusEngine + RAGMemory + CodeSandbox initialized")
|
| 7435 |
|
| 7436 |
# Auto-discover new models from DuckDuckGo, OpenRouter, etc.
|
| 7437 |
try:
|