HackerBol commited on
Commit
0aa1da7
·
verified ·
1 Parent(s): a2f7740

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +317 -0
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: