diff --git "a/PackedLLM.py" "b/PackedLLM.py" new file mode 100644--- /dev/null +++ "b/PackedLLM.py" @@ -0,0 +1,7529 @@ +from __future__ import annotations +'''PackedLLM, By: Chance Brownfield-|-HiMindAi@proton.me''' +import ast +import argparse +import base64 +import contextlib +import dataclasses +import hashlib +import importlib +import importlib.util +import io +import json +import lzma +import math +import os +import platform +import queue +import re +import shutil +import subprocess +import sys +import tempfile +import textwrap +import threading +import time +import traceback +import types +import uuid +import zipfile +from collections import OrderedDict, defaultdict, deque +from dataclasses import dataclass, field, asdict +from datetime import datetime +from pathlib import Path +from typing import ( + Any, Callable, Dict, Iterable, List, Mapping, + MutableMapping, Optional, Sequence, Tuple, Union +) +from urllib.parse import urlparse, parse_qs, quote, unquote +from multiprocessing import Process, Queue, get_context +import concurrent.futures +import numpy as np +import psutil +import requests +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch import Tensor +try: + from transformers import ( + MarianMTModel, + MarianTokenizer, + AutoModelForSeq2SeqLM, + AutoTokenizer, + ) + _HAS_TRANSFORMERS = True +except ImportError: + _HAS_TRANSFORMERS = False + MarianMTModel = MarianTokenizer = None + AutoModelForSeq2SeqLM = AutoTokenizer = None + +try: + from sentence_transformers import SentenceTransformer, util + _HAS_SENTENCE_TRANSFORMERS = True +except ImportError: + _HAS_SENTENCE_TRANSFORMERS = False +try: + import fitz # PyMuPDF + _HAS_PYMUPDF = True +except ImportError: + _HAS_PYMUPDF = False +try: + from sklearn.cluster import KMeans, AgglomerativeClustering + from sklearn.decomposition import PCA + from sklearn.metrics.pairwise import cosine_similarity + _HAS_SKLEARN = True +except ImportError: + _HAS_SKLEARN = False + KMeans = AgglomerativeClustering = PCA = cosine_similarity = None +try: + import spacy + _HAS_SPACY = True +except ImportError as e: + raise RuntimeError(f"spaCy is required: {e}") +try: + from bs4 import BeautifulSoup +except ImportError: + BeautifulSoup = None +try: + import trafilatura +except ImportError: + trafilatura = None +try: + from readability import Document +except ImportError: + Document = None +try: + from newspaper import Article +except ImportError: + Article = None +try: + from goose3 import Goose +except ImportError: + Goose = None +try: + from boilerpy3 import extractors +except ImportError: + extractors = None +try: + from inscriptis import get_text as inscriptis_text +except ImportError: + inscriptis_text = None +try: + from lxml import html as lxml_html +except ImportError: + lxml_html = None +try: + from youtube_transcript_api import YouTubeTranscriptApi +except ImportError: + YouTubeTranscriptApi = None +try: + from llama_cpp import Llama + _HAS_LLAMA_CPP = True +except ImportError: + _HAS_LLAMA_CPP = False + Llama = None +try: + import wgpu + _HAS_WGPU = True +except ImportError: + _HAS_WGPU = False +try: + from huggingface_hub import snapshot_download + _HAS_HF_HUB = True +except ImportError: + _HAS_HF_HUB = False +try: + from safetensors.torch import load_file as safetensors_load +except ImportError: + safetensors_load = None +MODEL_DIR = Path("models") +EMBEDDING_PATH = MODEL_DIR / "all-MiniLM-L6-v2" +SUMMARIZER_PATH = MODEL_DIR / "distilbart-cnn-12-6" +SPACY_MODEL_PATH = MODEL_DIR / "spacy" / "en_core_web_sm" +SPACY_MODEL_NAME = "en_core_web_sm" +DEFAULT_CHECKPOINT_PATH = "LM.pt" +DEFAULT_BUNDLE_PATH = "PackedLM.pt" +DEFAULT_IMAGE_TEST_SOURCE = "sample_img.png" +DEFAULT_ZH_EN_DIR = MODEL_DIR / "opus-mt-zh-en" +_CHUNK_BYTES = 32 * 1024 * 1024 +_CODE_FENCE_RE = re.compile(r"```(?:python)?\s*\n(.*?)```", re.DOTALL | re.IGNORECASE) +CHINESE_RE = re.compile(r"[\u4e00-\u9fff]") +CHINESE_SPAN_RE = re.compile( + r"[\u4e00-\u9fff]+(?:[\u3000-\u303F\uFF00-\uFFEF\u2000-\u206F" + r"\u2E00-\u2E7F\u3000-\u303F\uFF00-\uFFEF\s,.;:!?\-—()\[\]{},。!?、;:]+" + r"[\u4e00-\u9fff]+)*" +) +GGUF_EMBED_FILENAME = "jina-embeddings-v3-Q8_0.gguf" +for p in [MODEL_DIR, EMBEDDING_PATH, SUMMARIZER_PATH, SPACY_MODEL_PATH.parent]: + p.mkdir(parents=True, exist_ok=True) + +def _extract_python_code(text: str) -> str: + if not isinstance(text, str): + return "" + text = text.strip() + + fences = _CODE_FENCE_RE.findall(text) + candidates = [f.strip() for f in fences] if fences else [text] + + for candidate in candidates: + cleaned = _strip_to_valid_python(candidate) + if cleaned: + return cleaned + return text + +def _strip_to_valid_python(code: str) -> str: + try: + ast.parse(code) + return code + except SyntaxError: + pass + + lines = code.splitlines() + + for start in range(1, min(len(lines), 10) + 1): + candidate = "\n".join(lines[start:]) + try: + ast.parse(candidate) + return candidate + except SyntaxError: + continue + + for end in range(len(lines) - 1, max(len(lines) - 10, 0), -1): + candidate = "\n".join(lines[:end]) + try: + ast.parse(candidate) + return candidate + except SyntaxError: + continue + + return "" + +def _json_dumps(obj: Any) -> str: + return json.dumps(obj, ensure_ascii=False, default=str) + +def _parse_json_safe(text: Any) -> Any: + if not isinstance(text, str): + return None + + cleaned = text.strip() + if cleaned.startswith("```"): + lines = cleaned.splitlines() + if lines and lines[-1].strip() == "```": + cleaned = "\n".join(lines[1:-1]) + else: + cleaned = "\n".join(lines[1:]) + + try: + return json.loads(cleaned) + except Exception: + for start_char, end_char in [("{", "}"), ("[", "]")]: + si = cleaned.find(start_char) + ei = cleaned.rfind(end_char) + if si != -1 and ei != -1 and ei > si: + try: + return json.loads(cleaned[si:ei + 1]) + except Exception: + pass + return None + +def _safe_import_class(name: str) -> Optional[type]: + try: + frame = inspect.stack()[2].frame + cls = frame.f_globals.get(name) or builtins.__dict__.get(name) + return cls if isinstance(cls, type) else None + except Exception: + return None + +def _safe_call(obj: Any, name: str, *args: Any, default: Any = None, **kwargs: Any) -> Any: + fn = getattr(obj, name, None) + if not callable(fn): + return default + try: + return fn(*args, **kwargs) + except Exception: + return default + +def _bytes_to_chunks(data: bytes, chunk_size: int = _CHUNK_BYTES) -> List[bytes]: + return [data[i: i + chunk_size] for i in range(0, max(len(data), 1), chunk_size)] + +def _chunks_to_bytes(chunks: List[bytes]) -> bytes: + return b"".join(chunks) + +def _read_file_chunked(path: Optional[Union[str, Path]]) -> Optional[List[bytes]]: + if not path: + return None + p = Path(path) + if not p.exists(): + return None + chunks: List[bytes] = [] + try: + with open(p, "rb") as fh: + while True: + chunk = fh.read(_CHUNK_BYTES) + if not chunk: + break + chunks.append(chunk) + except Exception: + return None + return chunks if chunks else [b""] + +def _write_chunks_to_temp(chunks: Optional[List[bytes]], suffix: str, prefix: str = "packedllm_") -> Optional[str]: + if not chunks: + return None + fd, path = tempfile.mkstemp(prefix=prefix, suffix=suffix) + os.close(fd) + try: + with open(path, "wb") as fh: + for chunk in chunks: + fh.write(chunk) + except Exception: + try: + os.unlink(path) + except Exception: + pass + return None + return path + +def _normalise_expert_name(name: str) -> str: + s = re.sub(r"(?<=[a-z0-9])([A-Z])", r"_\1", name) + return s.lower() + +def _expert_names_canonical(names: List[str]) -> List[str]: + seen: set = set() + out: List[str] = [] + for n in names: + key = _normalise_expert_name(n) + if key not in seen: + seen.add(key) + out.append(key) + return out + +def capture_telemetry() -> Dict[str, Any]: + process = psutil.Process(os.getpid()) + cpu_total_pct = psutil.cpu_percent(interval=None) + cpu_process_pct = process.cpu_percent(interval=None) + ram_info = psutil.virtual_memory() + + metrics: Dict[str, Any] = { + "timestamp_ns": time.perf_counter_ns(), + "cpu": { + "system_total_percent": cpu_total_pct, + "process_percent": cpu_process_pct, + }, + "ram": { + "system_total_gb": ram_info.total / (1024 ** 3), + "system_available_gb": ram_info.available / (1024 ** 3), + "system_used_gb": ram_info.used / (1024 ** 3), + "process_rss_gb": process.memory_info().rss / (1024 ** 3), + }, + "gpu_hardware_metrics": { + "driver_detected": False, + "device_name": "None", + "total_vram_gb": 0.0, + "used_vram_gb": 0.0, + "free_vram_gb": 0.0, + "gpu_utilization_percent": 0.0, + }, + } + + try: + cmd = ( + "nvidia-smi --query-gpu=name,memory.total,memory.free,memory.used," + "utilization.gpu --format=csv,noheader,nounits" + ) + output = subprocess.check_output(cmd.split(), stderr=subprocess.DEVNULL).decode("ascii").strip() + if output: + parts = [p.strip() for p in output.split(",")] + metrics["gpu_hardware_metrics"] = { + "driver_detected": True, + "device_name": parts[0], + "total_vram_gb": float(parts[1]) / 1024.0, + "free_vram_gb": float(parts[2]) / 1024.0, + "used_vram_gb": float(parts[3]) / 1024.0, + "gpu_utilization_percent": float(parts[4]), + } + except Exception: + pass + + return metrics + +def calculate_delta(start: Dict[str, Any], end: Dict[str, Any]) -> Dict[str, Any]: + s_gpu = start["gpu_hardware_metrics"] + e_gpu = end["gpu_hardware_metrics"] + vram_delta = (e_gpu["used_vram_gb"] - s_gpu["used_vram_gb"]) if e_gpu["driver_detected"] else 0.0 + gpu_util = e_gpu["gpu_utilization_percent"] if e_gpu["driver_detected"] else 0.0 + return { + "ram_process_delta_gb": end["ram"]["process_rss_gb"] - start["ram"]["process_rss_gb"], + "vram_allocated_delta_gb": vram_delta, + "gpu_instantaneous_utilization_pct": gpu_util, + "cpu_system_delta_pct": end["cpu"]["system_total_percent"] - start["cpu"]["system_total_percent"], + } + +def normalize_unicode(s: str) -> str: + s = unicodedata.normalize("NFKC", s) + s = re.sub(r"[\u200B-\u200F\uFEFF\u00AD]", "", s) + s = re.sub(r"[\x00-\x1F\x7F]", "", s) + return s + +def canonicalize_numbers(s: str) -> str: + return re.sub(r"\d+\.\d+|\d+", "N", s) + +def strip_latex_wrappers(s: str) -> str: + s = s.replace("\\[", "").replace("\\]", "") + s = s.replace("\\(", "").replace("\\)", "") + s = re.sub(r"\$+", "", s) + return s + +def semantic_key(line: str) -> str: + line = line.strip().lower() + line = normalize_unicode(line) + line = strip_latex_wrappers(line) + line = re.sub(r"\\frac\{([^}]*)}\{([^}]*)}", r"frac(\1,\2)", line) + line = re.sub(r"\^{\s*([^}]*)\s*}", r"^(\1)", line) + line = canonicalize_numbers(line) + line = re.sub(r"\s+", " ", line) + return line.strip() + +def collapse_repeated_blocks_with_report(text: str, block_size: int = 2) -> Tuple[str, List[str]]: + lines = [l for l in text.splitlines() if l.strip()] + out: List[str] = [] + seen = set() + removed: List[str] = [] + i = 0 + while i < len(lines): + block_lines = lines[i:i+block_size] + block_keys = tuple(semantic_key(l) for l in block_lines) + if len(block_keys) < block_size: + out.extend(lines[i:]) + break + if block_keys in seen: + removed.extend(block_lines) + i += 1 + continue + seen.add(block_keys) + out.extend(block_lines) + i += block_size + return "\n".join(out), removed + +def collapse_repeated_semantic_lines_with_report(text: str, max_repeat: int = 1) -> Tuple[str, List[str]]: + out: List[str] = [] + removed: List[str] = [] + prev_key = None + count = 0 + for line in text.splitlines(): + if not line.strip(): + out.append(line) + prev_key = None + count = 0 + continue + k = semantic_key(line) + if k == prev_key: + count += 1 + if count > max_repeat: + removed.append(line) + continue + else: + prev_key = k + count = 0 + out.append(line) + return "\n".join(out), removed + +def collapse_repeated_lines(text: str, block_size: int = 2, max_repeat: int = 1, passes: int = 2, verbose: bool = True) -> str: + out = text or "" + total_removed: List[str] = [] + + for _ in range(max(1, int(passes))): + out, removed_blocks = collapse_repeated_blocks_with_report(out, block_size=block_size) + total_removed.extend(removed_blocks) + out, removed_lines = collapse_repeated_semantic_lines_with_report(out, max_repeat=max_repeat) + total_removed.extend(removed_lines) + + seen = set() + unique_removed = [] + for r in total_removed: + if r not in seen: + seen.add(r) + unique_removed.append(r) + + if verbose: + if unique_removed: + print(f"[collapse_repeated_lines] Removed {len(unique_removed)} unique repeated line(s)/block(s). Examples:") + for ex in unique_removed[:50]: + print(f"- {ex}") + else: + print("[collapse_repeated_lines] No repeated blocks or semantic-line repeats detected.") + + return out.strip() +def _now_iso() -> str: + return datetime.utcnow().isoformat() + +def _norm_ws(text: str) -> str: + return re.sub(r"\s+", " ", (text or "")).strip() + +def _safe_json_dumps(obj: Any) -> str: + return json.dumps(obj, ensure_ascii=False, sort_keys=True, separators=(",", ":")) + +def _safe_json_loads(text: str, default: Any = None) -> Any: + try: + return json.loads(text) + except Exception: + return default + +def _maybe_list(x: Any) -> List[Any]: + if x is None: + return [] + if isinstance(x, list): + return x + if isinstance(x, tuple): + return list(x) + return [x] + +def _normalize_whitespace(text: str) -> str: + return re.sub(r"\s+", " ", text or "").strip() + +def split_sentences(text: str) -> List[str]: + text = _normalize_whitespace(text) + if not text: + return [] + parts = re.split(r"(?<=[.!?])\s+", text) + return [p.strip() for p in parts if p.strip()] + +def _safe_hash(text: str) -> int: + return hash(_normalize_whitespace(text)) + +def _ensure_min_text(text: str, fallback: str = "") -> str: + text = _normalize_whitespace(text) + if text: + return text + return _normalize_whitespace(fallback) + +class FileManager: + def __init__(self, base_dir: str): + self.base_dir = os.path.abspath(base_dir) + self.global_dir = os.path.join(self.base_dir, "global_data") + os.makedirs(self.global_dir, exist_ok=True) + + def abs_path(self, path: str) -> str: + return os.path.abspath(path) + + def copy_to_global(self, src: str, dest_name: Optional[str] = None) -> str: + dest_name = dest_name or os.path.basename(src) + dest = os.path.join(self.global_dir, dest_name) + if os.path.abspath(src) == os.path.abspath(dest): + return dest + if not os.path.exists(dest): + shutil.copy2(src, dest) + return dest + + def write_bytes_to_global(self, data: bytes, dest_name: str) -> str: + dest = os.path.join(self.global_dir, dest_name) + with open(dest, "wb") as f: + f.write(data) + return dest + + def hardlink_or_copy(self, src: str, dst: str): + try: + os.link(src, dst) + except Exception: + shutil.copy2(src, dst) + + def atomic_replace(self, src_tmp: str, dest: str): + os.replace(src_tmp, dest) + + def compute_sha256(self, path: str) -> str: + h = hashlib.sha256() + with open(path, "rb") as f: + for chunk in iter(lambda: f.read(1 << 20), b""): + h.update(chunk) + return h.hexdigest() + +class CodeBoxError(Exception): + pass + +class AssetNotFoundError(CodeBoxError): + pass + +class RunnerCacheError(CodeBoxError): + pass + +class LRUCache: + def __init__(self, capacity: int = 2): + self.capacity = capacity + self.cache = OrderedDict() + + def get(self, key): + if key not in self.cache: + return None + self.cache.move_to_end(key) + return self.cache[key] + + def put(self, key, value): + if key in self.cache: + self.cache.move_to_end(key) + self.cache[key] = value + return + self.cache[key] = value + if len(self.cache) > self.capacity: + old_key, old_val = self.cache.popitem(last=False) + try: + if hasattr(old_val, "close"): + old_val.close() + if hasattr(old_val, "cleanup"): + old_val.cleanup() + except Exception: + pass + try: + import torch + del old_val + torch.cuda.empty_cache() + except Exception: + pass + + def keys(self): + return list(self.cache.keys()) + + def clear(self): + self.cache.clear() + try: + import torch + torch.cuda.empty_cache() + except Exception: + pass + +# The CodeBox +class CodeBox: + ASSETS_FILENAME = "assets.pt" + ASSET_SCHEMA_VERSION = 1 + + def __init__(self, base_dir: str = "./codebox_storage", runner_cache_capacity: int = 2): + self.base_dir = os.path.abspath(base_dir) + self.envs_dir = os.path.join(self.base_dir, "envs") + self.file_manager = FileManager(self.base_dir) + os.makedirs(self.envs_dir, exist_ok=True) + self.env_dic: Dict[str, Dict[str, Any]] = {} + self.code_bank: Dict[str, Dict[str, Any]] = {} + self.asset_registry: Dict[str, Dict[str, Any]] = {} + self._load_registry() + self._runner_cache = LRUCache(capacity=runner_cache_capacity) + self._ensure_loader_template() + + def _registry_path(self) -> str: + return os.path.join(self.file_manager.global_dir, self.ASSETS_FILENAME) + + def _persist_registry(self): + tmp_fd, tmp_path = tempfile.mkstemp(dir=self.file_manager.global_dir) + os.close(tmp_fd) + payload = { + "schema_version": self.ASSET_SCHEMA_VERSION, + "assets": self.asset_registry + } + torch.save(payload, tmp_path) + self.file_manager.atomic_replace(tmp_path, self._registry_path()) + + def _load_registry(self): + path = self._registry_path() + if os.path.exists(path): + try: + payload = torch.load(path) + if isinstance(payload, dict) and "assets" in payload: + self.asset_registry = payload["assets"] + else: + self.asset_registry = payload + except Exception: + corrupted = path + f".corrupt.{int(time.time())}" + shutil.move(path, corrupted) + self.asset_registry = {} + else: + self.asset_registry = {} + + def register_asset(self, alias: str, file_path: Optional[str] = None, + asset_type: str = "bin", metadata: Dict = None, + embed_bytes: Optional[bytes] = None, force: bool = False) -> Dict[str, Any]: + metadata = metadata or {} + if embed_bytes is not None: + bytes_name = f"{alias}.embedded" + dest = self.file_manager.write_bytes_to_global(embed_bytes, bytes_name) + sha = self.file_manager.compute_sha256(dest) + entry = { + "source_path": dest, + "type": asset_type, + "metadata": metadata, + "embedded": True, + "bytes_name": bytes_name, + "sha256": sha, + "registered_at": time.time() + } + self.asset_registry[alias] = entry + self._persist_registry() + return entry + + if not file_path: + raise ValueError("Provide either file_path or embed_bytes") + + src_abs = os.path.abspath(file_path) + dest = self.file_manager.copy_to_global(src_abs, dest_name=os.path.basename(src_abs)) + sha = self.file_manager.compute_sha256(dest) + entry = { + "source_path": dest, + "type": asset_type, + "metadata": metadata, + "embedded": False, + "sha256": sha, + "registered_at": time.time() + } + if alias in self.asset_registry and not force: + if self.asset_registry[alias].get("sha256") == sha: + return self.asset_registry[alias] + self.asset_registry[alias] = entry + self._persist_registry() + return entry + + def unregister_asset(self, alias: str): + if alias in self.asset_registry: + del self.asset_registry[alias] + self._persist_registry() + + def _ensure_loader_template(self): + loader_path = os.path.join(self.file_manager.global_dir, "_codebox_loader.py") + if os.path.exists(loader_path): + return + + loader_code = r''' +import os +import json + +# Try optional heavy deps; if missing, fall back to JSON registry and path-only behavior. +try: + import torch as _torch +except Exception: + _torch = None + +try: + from safetensors.torch import load_file as _safetensors_load +except Exception: + _safetensors_load = None + +def _registry_pt_path(assets_dir): + return os.path.join(assets_dir, "assets.pt") + +def _registry_json_path(assets_dir): + return os.path.join(assets_dir, "assets.json") + +def _load_registry(assets_dir): + # Prefer torch payload if torch is available and file exists + pt_path = _registry_pt_path(assets_dir) + json_path = _registry_json_path(assets_dir) + if _torch is not None and os.path.exists(pt_path): + try: + payload = _torch.load(pt_path) + if isinstance(payload, dict) and "assets" in payload: + return payload["assets"] + return payload + except Exception: + # fall through to json + pass + if os.path.exists(json_path): + with open(json_path, "r", encoding="utf-8") as f: + return json.load(f) + # last resort: try to load pt even without torch (will raise) + if os.path.exists(pt_path): + raise RuntimeError("Torch not available to read assets.pt; install torch or ensure assets.json exists.") + return {} + +def load_asset(alias): + assets_dir = os.environ.get("CODEBOX_ASSETS_DIR") + if not assets_dir: + raise RuntimeError("CODEBOX_ASSETS_DIR not set") + registry = _load_registry(assets_dir) + entry = registry.get(alias) + if not entry: + raise KeyError(f"Asset '{alias}' not found in registry") + path = entry["source_path"] + typ = entry.get("type", "bin") + if typ == "safetensors": + if _safetensors_load is None: + return path + return _safetensors_load(path) + if typ == "pt": + if _torch is None: + raise RuntimeError("Torch not available in this environment to load .pt assets.") + return _torch.load(path, map_location="cpu") + if typ == "json": + with open(path, "r", encoding="utf-8") as f: + return json.load(f) + return path +''' + loader_code = textwrap.dedent(loader_code) + with open(loader_path, "w", encoding="utf-8") as f: + f.write(loader_code) + + def _sync_required_assets(self, working_dir: str, required_assets: Optional[List[str]] = None): + registry_dst_pt = os.path.join(working_dir, self.ASSETS_FILENAME) + registry_dst_json = os.path.join(working_dir, "assets.json") + payload = {"schema_version": self.ASSET_SCHEMA_VERSION, "assets": self.asset_registry} + tmp_fd, tmp_path = tempfile.mkstemp(dir=working_dir) + os.close(tmp_fd) + torch.save(payload, tmp_path) + os.replace(tmp_path, registry_dst_pt) + tmp_fd, tmp_path = tempfile.mkstemp(dir=working_dir) + os.close(tmp_fd) + with open(tmp_path, "w", encoding="utf-8") as f: + json.dump(self.asset_registry, f) + os.replace(tmp_path, registry_dst_json) + assets_to_mount = required_assets if required_assets else list(self.asset_registry.keys()) + for alias in assets_to_mount: + entry = self.asset_registry.get(alias) + if not entry: + continue + src = entry["source_path"] + target = os.path.join(working_dir, os.path.basename(src)) + if not os.path.exists(target): + try: + self.file_manager.hardlink_or_copy(src, target) + except Exception: + shutil.copy2(src, target) + + def _inject_loader_into_env(self, env_src_dir: str): + src = os.path.join(self.file_manager.global_dir, "_codebox_loader.py") + dst = os.path.join(env_src_dir, "_codebox_loader.py") + if not os.path.exists(dst): + shutil.copy2(src, dst) + + def _get_python_bin(self, venv_path: str) -> str: + if os.name == 'nt': + return os.path.join(venv_path, "Scripts", "python.exe") + return os.path.join(venv_path, "bin", "python") + + def create_venv(self, venv_id: str, requirements: List[str] = None) -> str: + venv_path = os.path.join(self.envs_dir, venv_id) + if venv_id not in self.env_dic: + subprocess.run([sys.executable, "-m", "venv", venv_path], check=True) + os.makedirs(os.path.join(venv_path, "src"), exist_ok=True) + self.env_dic[venv_id] = {"path": venv_path, "packages": []} + # inject loader template into src + self._inject_loader_into_env(os.path.join(venv_path, "src")) + if requirements: + self.install_packages(venv_id, requirements) + return venv_path + + def install_packages(self, venv_id: str, packages: List[str]): + if venv_id not in self.env_dic: + self.create_venv(venv_id) + python_bin = self._get_python_bin(self.env_dic[venv_id]["path"]) + cmd = [python_bin, "-m", "pip", "install", "--quiet"] + packages + subprocess.run(cmd, check=True) + existing = set(self.env_dic[venv_id]["packages"]) + for pkg in packages: + if pkg not in existing: + self.env_dic[venv_id]["packages"].append(pkg) + + def export_venv(self, venv_id: str) -> str: + if venv_id not in self.env_dic: + raise ValueError(f"Environment '{venv_id}' does not exist.") + python_bin = self._get_python_bin(self.env_dic[venv_id]["path"]) + res = subprocess.run([python_bin, "-m", "pip", "freeze"], capture_output=True, text=True) + manifest = { + "venv_id": venv_id, + "pip_freeze": res.stdout.splitlines(), + "metadata": {k: v for k, v in self.env_dic[venv_id].items() if k != "path"} + } + return json.dumps(manifest, indent=2) + + def import_venv(self, manifest_json: str): + manifest = json.loads(manifest_json) + venv_id = manifest["venv_id"] + self.create_venv(venv_id, requirements=manifest["pip_freeze"]) + + def _execute_supervised(self, python_bin: str, script_path: str, working_dir: str, + timeout: Optional[int] = 30, max_ram_mb: int = 4096, + required_assets: Optional[List[str]] = None) -> Dict[str, Any]: + self._sync_required_assets(working_dir, required_assets) + env_vars = os.environ.copy() + env_vars["PYTHONPATH"] = working_dir + env_vars["CODEBOX_ASSETS_DIR"] = working_dir + proc = subprocess.Popen( + [python_bin, script_path], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=working_dir, + env=env_vars, + text=True + ) + + alarms = [] + MAX_CPU = 95.0 + + def monitor(): + try: + p = psutil.Process(proc.pid) + while proc.poll() is None: + mem_mb = p.memory_info().rss / (1024 * 1024) + cpu = p.cpu_percent(interval=0.2) + if mem_mb > max_ram_mb: + alarms.append(f"RESOURCE KILL: Memory usage exceeded ({mem_mb:.1f}MB > {max_ram_mb}MB)") + proc.kill() + break + if cpu > MAX_CPU: + alarms.append(f"RESOURCE WARNING: Sustained CPU spike ({cpu}%)") + except psutil.NoSuchProcess: + pass + + mon_thread = threading.Thread(target=monitor, daemon=True) + mon_thread.start() + + try: + stdout, stderr = proc.communicate(timeout=timeout) + except subprocess.TimeoutExpired: + proc.kill() + stdout, stderr = proc.communicate() + alarms.append(f"RESOURCE KILL: Code execution timed out ({timeout}s limit).") + + return { + "stdout": stdout.strip(), + "stderr": stderr.strip(), + "success": proc.returncode == 0 and not any("KILL" in a for a in alarms), + "exit_code": proc.returncode, + "technical_alarms": alarms + } + + def run_code(self, code_block: str, venv_id: str = "default", requirements: List[str] = None, + timeout: Optional[int] = 30, max_ram_mb: int = 4096, + required_assets: Optional[List[str]] = None) -> Dict[str, Any]: + is_temp = False + if requirements: + venv_id = f"temp_{int(time.time())}" + self.create_venv(venv_id, requirements) + is_temp = True + elif venv_id not in self.env_dic: + self.create_venv(venv_id) + env_meta = self.env_dic[venv_id] + src_dir = os.path.join(env_meta["path"], "src") + python_bin = self._get_python_bin(env_meta["path"]) + temp_script = os.path.join(src_dir, f"_run_{int(time.time())}.py") + with open(temp_script, 'w', encoding='utf-8') as f: + f.write(code_block) + try: + result = self._execute_supervised(python_bin, temp_script, src_dir, timeout, max_ram_mb, required_assets) + finally: + if os.path.exists(temp_script): + os.remove(temp_script) + if is_temp: + shutil.rmtree(env_meta["path"], ignore_errors=True) + del self.env_dic[venv_id] + + return result + + def save_script(self, code_id: str, venv_id: str, source_code: str): + if venv_id not in self.env_dic: + self.create_venv(venv_id) + src_dir = os.path.join(self.env_dic[venv_id]["path"], "src") + filepath = os.path.join(src_dir, f"{code_id}.py") + with open(filepath, 'w', encoding='utf-8') as f: + f.write(source_code) + self.code_bank[code_id] = {"venv_id": venv_id, "filepath": filepath} + self._inject_loader_into_env(src_dir) + + def call_function(self, code_id: str = None, function_call: str = None, function_map: Dict[str, Any] = None, + timeout: Optional[int] = 30, max_ram_mb: int = 4096, + required_assets: Optional[List[str]] = None) -> Dict[str, Any]: + if function_map: + first_step = list(function_map.values())[0] + venv_id = self.code_bank[first_step["code_id"]]["venv_id"] + env_meta = self.env_dic[venv_id] + src_dir = os.path.join(env_meta["path"], "src") + python_bin = self._get_python_bin(env_meta["path"]) + lines = ["import json\nimport sys\ncontext = {}\n"] + for step, data in function_map.items(): + c_id, f_name = data["code_id"], data["function"] + args = data.get("args", {}) + out_var = data.get("output_var", f"out_{step}") + lines.append(f"import {c_id}") + arg_strs = [] + for k, v in args.items(): + if isinstance(v, str) and v.startswith("$"): + arg_strs.append(f"{k}=context['{v[1:]}']") + else: + arg_strs.append(f"{k}={repr(v)}") + lines.append(f"try:\n context['{out_var}'] = {c_id}.{f_name}({', '.join(arg_strs)})") + lines.append(f"except Exception as e:\n print(f'Pipeline failed at {step}: {{e}}', file=sys.stderr)\n sys.exit(1)\n") + lines.append("print(json.dumps(context))") + wrapper_code = "\n".join(lines) + wrapper_path = os.path.join(src_dir, "_dag_runner.py") + with open(wrapper_path, 'w', encoding='utf-8') as f: + f.write(wrapper_code) + try: + result = self._execute_supervised(python_bin, wrapper_path, src_dir, timeout, max_ram_mb, required_assets) + finally: + if os.path.exists(wrapper_path): + os.remove(wrapper_path) + return result + + elif code_id and function_call: + import ast + try: + tree = ast.parse(function_call) + expr = tree.body[0].value + if not isinstance(expr, ast.Call): + raise ValueError("Target signature is not a valid call statement.") + func_name = expr.func.id + extracted_args = {} + for keyword in expr.keywords: + extracted_args[keyword.arg] = ast.literal_eval(keyword.value) + except Exception as e: + raise ValueError(f"AST Function Call Parser failed on expression matching: {e}") + macro_map = { + "step_1": { + "code_id": code_id, + "function": func_name, + "args": extracted_args, + "output_var": "result" + } + } + return self.call_function(function_map=macro_map, timeout=timeout, max_ram_mb=max_ram_mb, required_assets=required_assets) + else: + raise ValueError("Provide either code_id + function_call, or function_map") + + def get_runner(self, key: str): + return self._runner_cache.get(key) + + def put_runner(self, key: str, runner_obj): + self._runner_cache.put(key, runner_obj) + + def prune_cache(self, days_unused: int = 7, logger=None): + cutoff = time.time() - days_unused * 86400 + assets_to_keep = {self.ASSETS_FILENAME, "_codebox_loader.py"} + try: + with os.scandir(self.file_manager.global_dir) as it: + for entry in it: + try: + if entry.is_dir(): + continue + name = entry.name + if name in assets_to_keep: + continue + mtime = entry.stat().st_mtime + if mtime < cutoff: + try: + os.remove(entry.path) + except Exception as e: + if logger: + logger.warning("Failed to remove %s: %s", entry.path, e) + except FileNotFoundError: + continue + except PermissionError: + if logger: + logger.warning("Permission denied pruning %s", entry.path) + continue + except Exception as e: + if logger: + logger.error("Prune cache failed for %s: %s", self.file_manager.global_dir, e) + + def resolve_asset_path(self, alias: str) -> str: + entry = self.asset_registry.get(alias) + if not entry: + raise AssetNotFoundError(alias) + return entry["source_path"] + +class Box: + """ + Persistent wrapper around CodeBox. + + Resolution order: + + 1. box_location argument + 2. AppData config location + 3. Create new CodeBox.pt + """ + + APP_NAME = "CodeBox" + CONFIG_FILE = "box_config.json" + DEFAULT_MODEL_FILE = "CodeBox.pt" + + def __init__( + self, + box_location: Optional[str] = None, + base_dir: Optional[str] = None, + runner_cache_capacity: int = 2, + ): + self._model_path = self._resolve_model_path(box_location) + + if os.path.exists(self._model_path): + self.model = torch.load(self._model_path) + else: + self.model = CodeBox( + base_dir=base_dir or self._default_storage_dir(), + runner_cache_capacity=runner_cache_capacity, + ) + self.save() + + @classmethod + def _appdata_dir(cls): + if os.name == "nt": + root = os.getenv("APPDATA") + else: + root = os.path.expanduser("~/.config") + + path = os.path.join(root, cls.APP_NAME) + os.makedirs(path, exist_ok=True) + return path + + @classmethod + def _config_path(cls): + return os.path.join(cls._appdata_dir(), cls.CONFIG_FILE) + + @classmethod + def _default_storage_dir(cls): + path = os.path.join(cls._appdata_dir(), "storage") + os.makedirs(path, exist_ok=True) + return path + + @classmethod + def _default_model_path(cls): + return os.path.join(cls._appdata_dir(), cls.DEFAULT_MODEL_FILE) + + def _resolve_model_path(self, box_location): + + if box_location: + path = os.path.abspath(box_location) + self._write_config(path) + return path + + config = self._read_config() + + if config: + saved_path = config.get("box_location") + + if saved_path and os.path.exists(saved_path): + return saved_path + + path = self._default_model_path() + + self._write_config(path) + + return path + + def _read_config(self): + cfg = self._config_path() + + if not os.path.exists(cfg): + return {} + + try: + with open(cfg, "r", encoding="utf-8") as f: + return json.load(f) + except Exception: + return {} + + def _write_config(self, model_path): + cfg = self._config_path() + + with open(cfg, "w", encoding="utf-8") as f: + json.dump( + { + "box_location": os.path.abspath(model_path) + }, + f, + indent=2, + ) + + def save(self): + torch.save(self.model, self._model_path) + + def save_as(self, path): + path = os.path.abspath(path) + + torch.save(self.model, path) + + self._model_path = path + + self._write_config(path) + + @classmethod + def load(cls, path): + return cls(box_location=path) + + def register_asset(self, *args, **kwargs): + result = self.model.register_asset(*args, **kwargs) + self.save() + return result + + def unregister_asset(self, *args, **kwargs): + result = self.model.unregister_asset(*args, **kwargs) + self.save() + return result + + def create_venv(self, *args, **kwargs): + result = self.model.create_venv(*args, **kwargs) + self.save() + return result + + def install_packages(self, *args, **kwargs): + result = self.model.install_packages(*args, **kwargs) + self.save() + return result + + def save_script(self, *args, **kwargs): + result = self.model.save_script(*args, **kwargs) + self.save() + return result + + def put_runner(self, *args, **kwargs): + result = self.model.put_runner(*args, **kwargs) + self.save() + return result + + def __getattr__(self, name): + return getattr(self.model, name) + + def __contains__(self, alias): + return alias in self.model.asset_registry + + def __len__(self): + return len(self.model.asset_registry) + + def __repr__(self): + return ( + f"Box(" + f"assets={len(self.model.asset_registry)}, " + f"envs={len(self.model.env_dic)}, " + f"path='{self._model_path}')" + ) + + def close(self): + try: + self.model._runner_cache.clear() + except Exception: + pass + self.save() + + def __del__(self): + try: + self.close() + except Exception: + pass + +class TextModelBundle: + def __init__(self, model_dir: str = MODEL_DIR): + self.model_dir = model_dir + self.embedding_path = os.path.join(model_dir, "all-MiniLM-L6-v2") + self.summarizer_path = os.path.join(model_dir, "distilbart-cnn-12-6") + self.spacy_model_path = os.path.join(model_dir, "spacy", "en_core_web_sm") + self.spacy_model_name = SPACY_MODEL_NAME + + self.embedding_model = self._load_embeddings() + self.summarizer_model, self.tokenizer = self._load_summarizer() + self.nlp = self._load_spacy() + + def _load_embeddings(self): + if os.path.exists(self.embedding_path) and os.path.isdir(self.embedding_path): + return SentenceTransformer(self.embedding_path) + model = SentenceTransformer("all-MiniLM-L6-v2") + model.save(self.embedding_path) + return model + + def _load_summarizer(self): + if os.path.exists(self.summarizer_path) and os.path.isdir(self.summarizer_path): + model = AutoModelForSeq2SeqLM.from_pretrained(self.summarizer_path) + tokenizer = AutoTokenizer.from_pretrained(self.summarizer_path) + return model, tokenizer + model = AutoModelForSeq2SeqLM.from_pretrained("sshleifer/distilbart-cnn-12-6") + tokenizer = AutoTokenizer.from_pretrained("sshleifer/distilbart-cnn-12-6") + model.save_pretrained(self.summarizer_path) + tokenizer.save_pretrained(self.summarizer_path) + return model, tokenizer + + def _load_spacy(self): + try: + if os.path.exists(self.spacy_model_path): + return spacy.load(self.spacy_model_path) + return spacy.load(self.spacy_model_name) + except Exception: + nlp = spacy.blank("en") + if "sentencizer" not in nlp.pipe_names: + nlp.add_pipe("sentencizer") + return nlp + + def embed(self, texts, convert_to_tensor=True): + return self.embedding_model.encode(texts, convert_to_tensor=convert_to_tensor) + + def generate_summary(self, text: str, max_length: int = 300, min_length: int = 50) -> str: + text = _normalize_whitespace(text) + if not text: + return "" + + inputs = self.tokenizer( + text, + return_tensors="pt", + truncation=True, + max_length=1024, + ) + device = next(self.summarizer_model.parameters()).device + inputs = {k: v.to(device) for k, v in inputs.items()} + + with torch.no_grad(): + summary_ids = self.summarizer_model.generate( + **inputs, + max_length=max_length, + min_length=min_length, + num_beams=4, + early_stopping=True, + ) + return self.tokenizer.decode(summary_ids[0], skip_special_tokens=True) + +def chunk_text_by_context(text: str, bundle: TextModelBundle, num_chunks: int = 20) -> List[str]: + sentences = split_sentences(text) + if not sentences: + return [] + if len(sentences) == 1: + return [sentences[0]] + + embeddings = bundle.embed(sentences) + if embeddings.ndim != 2 or embeddings.shape[0] <= 1: + return [" ".join(sentences)] + + n_samples, n_features = embeddings.shape + n_components = max(1, min(num_chunks, n_samples, n_features)) + reduced = PCA(n_components=n_components).fit_transform(embeddings) + + k = min(num_chunks, n_samples) + clustering = AgglomerativeClustering(n_clusters=k) + labels = clustering.fit_predict(reduced) + + chunks: Dict[int, List[str]] = {} + for sent, lbl in zip(sentences, labels): + chunks.setdefault(int(lbl), []).append(sent) + + return [" ".join(chunks[i]) for i in sorted(chunks.keys())] + + +def safe_summarize_iterative(bundle: TextModelBundle, text: str, max_length: int = 500, min_length: int = 300, overlap: int = 100) -> str: + text = _normalize_whitespace(text) + if not text: + return "" + + word_threshold = max_length + if len(text.split()) <= word_threshold: + return text + + token_ids = bundle.tokenizer.encode(text, add_special_tokens=False) + if len(token_ids) <= 1024: + try: + return bundle.generate_summary(text, max_length=max_length, min_length=min_length) + except Exception: + return text + + sentences = split_sentences(text) + if len(sentences) > 1: + mid = len(sentences) // 2 + left = " ".join(sentences[:mid]) + right = " ".join(sentences[mid:]) + a = safe_summarize_iterative(bundle, left, max_length, min_length, overlap) + b = safe_summarize_iterative(bundle, right, max_length, min_length, overlap) + return _normalize_whitespace(f"{a} {b}") + + chunks = [] + start = 0 + while start < len(token_ids): + end = min(start + 1024, len(token_ids)) + chunk_tokens = token_ids[start:end] + chunk_text = bundle.tokenizer.decode( + chunk_tokens, + skip_special_tokens=True, + clean_up_tokenization_spaces=True, + ) + chunks.append(chunk_text) + if end == len(token_ids): + break + start = end - overlap + + summaries = [] + for chunk in chunks: + chunk = _normalize_whitespace(chunk) + if not chunk: + continue + if len(chunk.split()) <= word_threshold: + summaries.append(chunk) + continue + try: + summaries.append(bundle.generate_summary(chunk, max_length=max_length, min_length=min_length)) + except Exception: + summaries.append(chunk) + + combined = _normalize_whitespace(" ".join(summaries)) + if not combined: + return text + + if len(combined.split()) <= word_threshold: + return combined + return safe_summarize_iterative(bundle, combined, max_length, min_length, overlap) + + +def safe_summarize(bundle: TextModelBundle, text: str, max_length: int = 750, min_length: int = 500, overlap: int = 250, depth: int = 0, max_depth: int = 15) -> str: + text = _normalize_whitespace(text) + if not text: + return "" + + if depth > max_depth: + return safe_summarize_iterative(bundle, text, max_length=max_length, min_length=min_length, overlap=overlap) + + if len(text.split()) <= max_length: + return text + + token_ids = bundle.tokenizer.encode(text, add_special_tokens=False) + if len(token_ids) <= 1024: + try: + return bundle.generate_summary(text, max_length=max_length, min_length=min_length) + except Exception: + return text + + sentences = split_sentences(text) + if len(sentences) > 1: + mid = len(sentences) // 2 + left = " ".join(sentences[:mid]) + right = " ".join(sentences[mid:]) + try: + s1 = safe_summarize(bundle, left, max_length, min_length, overlap, depth + 1, max_depth) + s2 = safe_summarize(bundle, right, max_length, min_length, overlap, depth + 1, max_depth) + return safe_summarize(bundle, f"{s1} {s2}", max_length, min_length, overlap, depth + 1, max_depth) + except RecursionError: + return safe_summarize_iterative(bundle, text, max_length=max_length, min_length=min_length, overlap=overlap) + + pieces = [] + start = 0 + while start < len(token_ids): + end = min(start + 1024, len(token_ids)) + chunk_tokens = token_ids[start:end] + chunk_text = bundle.tokenizer.decode( + chunk_tokens, + skip_special_tokens=True, + clean_up_tokenization_spaces=True, + ) + pieces.append(chunk_text) + if end == len(token_ids): + break + start = end - overlap + + chunk_summaries = [] + for piece in pieces: + piece = _normalize_whitespace(piece) + if not piece: + continue + if len(piece.split()) <= max_length: + chunk_summaries.append(piece) + else: + try: + chunk_summaries.append(bundle.generate_summary(piece, max_length=max_length, min_length=min_length)) + except Exception: + chunk_summaries.append(piece) + + combined = _normalize_whitespace(" ".join(chunk_summaries)) + if not combined: + return text + if len(combined.split()) <= max_length: + return combined + return safe_summarize(bundle, combined, max_length, min_length, overlap, depth + 1, max_depth) + +def summarize_relevant_clusters(bundle: TextModelBundle, input_query: str, texts: List[str], similarity_threshold: Optional[float] = None, num_clusters: int = 12) -> List[str]: + texts = [_normalize_whitespace(t) for t in texts if _normalize_whitespace(t)] + if not texts: + return [] + + if len(texts) == 1: + return [safe_summarize(bundle, texts[0])] + + embeddings = bundle.embed(texts, convert_to_tensor=True) + sim_matrix = util.pytorch_cos_sim(embeddings, embeddings) + + if similarity_threshold is None: + if sim_matrix.size(0) > 1: + idx = torch.triu_indices(sim_matrix.size(0), sim_matrix.size(1), offset=1) + similarities = sim_matrix[idx[0], idx[1]] + similarity_threshold = similarities.mean().item() if similarities.numel() > 0 else 0.85 + else: + similarity_threshold = 0.85 + + keep_indices = [] + for i in range(len(texts)): + if not any(float(sim_matrix[i][j].item()) > similarity_threshold for j in keep_indices): + keep_indices.append(i) + + dedup_texts = [texts[i] for i in keep_indices] + if not dedup_texts: + dedup_texts = texts[:] + + dedup_embeddings = embeddings[keep_indices] if keep_indices else embeddings + n_clusters = min(num_clusters, len(dedup_texts)) + n_clusters = max(1, n_clusters) + + if len(dedup_texts) == 1: + return [safe_summarize(bundle, dedup_texts[0])] + + kmeans = KMeans(n_clusters=n_clusters, random_state=0, n_init="auto") + labels = kmeans.fit_predict(dedup_embeddings.cpu().numpy()) + + clusters: Dict[int, List[str]] = {} + for idx, lbl in enumerate(labels): + clusters.setdefault(int(lbl), []).append(dedup_texts[idx]) + + try: + doc = bundle.nlp(input_query) + keywords = {token.lemma_.lower() for token in doc if getattr(token, "pos_", "") in ("NOUN", "VERB", "ADJ", "PROPN")} + except Exception: + keywords = set() + + def is_cluster_relevant(cluster_texts: List[str]) -> bool: + if not keywords: + return True + joined = " ".join(cluster_texts).lower() + return any(k in joined for k in keywords) + + relevant_clusters = [c for c in clusters.values() if is_cluster_relevant(c)] + if not relevant_clusters: + relevant_clusters = list(clusters.values()) + + cluster_summaries = [] + for cluster in relevant_clusters: + combined = _normalize_whitespace(" ".join(cluster)) + if combined: + cluster_summaries.append(safe_summarize(bundle, combined)) + + if not cluster_summaries: + return [safe_summarize(bundle, " ".join(dedup_texts))] + + final_text = _normalize_whitespace(" ".join(cluster_summaries)) + return [safe_summarize(bundle, final_text)] + + +@dataclass +class PageCandidate: + title: str + url: str + snippet: str = "" + rank: float = 0.0 + + +@dataclass +class CrawlResult: + query: str + answer: str = "" + partial_texts: List[str] = field(default_factory=list) + used_candidates: List[str] = field(default_factory=list) + failed_candidates: List[str] = field(default_factory=list) + fallback_used: bool = False + elapsed_seconds: float = 0.0 + error: Optional[str] = None + +class CrawlWorker: + def __init__(self): + self.bundle = TextModelBundle() + self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=8) + self.session = requests.Session() + self.session.headers.update({ + "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" + ), + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Accept-Language": "en-US,en;q=0.5", + }) + + def close(self): + try: + self.executor.shutdown(wait=False, cancel_futures=True) + except Exception: + pass + try: + self.session.close() + except Exception: + pass + + def run_query(self, query: str, stats: Optional[dict] = None) -> CrawlResult: + t0 = time.perf_counter() + result = CrawlResult(query=query) + + try: + candidates = self.build_candidates(query) + if not candidates: + result.answer = f"No results found for: {query}" + result.fallback_used = True + return result + + target_successes = 5 + successful_texts: List[str] = [] + fallback_snippets: List[str] = [] + + for idx, cand in enumerate(candidates): + if len(successful_texts) >= target_successes: + break + + text = self.fetch_and_extract(cand.url, page_timeout=20) + if text and len(text.strip()) >= 80: + successful_texts.append(_normalize_whitespace(text)) + result.used_candidates.append(cand.url) + else: + result.failed_candidates.append(cand.url) + if cand.snippet: + fallback_snippets.append(f"{cand.title}. {cand.snippet}".strip()) + + if len(successful_texts) < target_successes: + for cand in candidates[len(successful_texts) + len(result.failed_candidates):]: + if len(successful_texts) >= target_successes: + break + if cand.url in result.used_candidates or cand.url in result.failed_candidates: + continue + text = self.fetch_and_extract(cand.url, page_timeout=20) + if text and len(text.strip()) >= 80: + successful_texts.append(_normalize_whitespace(text)) + result.used_candidates.append(cand.url) + else: + result.failed_candidates.append(cand.url) + if cand.snippet: + fallback_snippets.append(f"{cand.title}. {cand.snippet}".strip()) + + if successful_texts: + merged = " ".join(successful_texts) + chunks = chunk_text_by_context(merged, self.bundle, num_chunks=min(8, max(2, len(successful_texts)))) + summary_list = summarize_relevant_clusters(self.bundle, query, chunks, similarity_threshold=None, num_clusters=min(8, len(chunks))) + answer = _normalize_whitespace(" ".join(summary_list)) + result.answer = answer if answer else _normalize_whitespace(merged) + result.partial_texts = successful_texts + return result + + snippet_text = _normalize_whitespace(" ".join(fallback_snippets)) + if snippet_text: + result.answer = snippet_text + result.fallback_used = True + return result + + ranked_text = _normalize_whitespace(" ".join(f"{c.title}. {c.snippet}".strip() for c in candidates[:5])) + result.answer = ranked_text if ranked_text else f"No usable text found for: {query}" + result.fallback_used = True + return result + except Exception as e: + result.error = f"{e}\n{traceback.format_exc()}" + result.answer = result.answer or f"[ERROR] {e}" + return result + finally: + result.elapsed_seconds = time.perf_counter() - t0 + if stats is not None: + stats.setdefault("runs", []).append({ + "query": query, + "seconds": round(result.elapsed_seconds, 3), + "used_pages": len(result.used_candidates), + "failed_pages": len(result.failed_candidates), + "fallback_used": result.fallback_used, + "error": result.error, + }) + + def build_candidates(self, query: str, num_results: int = 15) -> List[PageCandidate]: + raw = [] + raw.extend(self.duckduckgo_search(query, num_results=num_results)) + raw.extend(self.resulthunter_search(query, num_results=num_results)) + raw.extend(self.google_search(query, num_results=num_results)) + deduped: List[PageCandidate] = [] + seen = set() + scored = [] + for title, url, snippet in raw: + norm = self.normalize_url(url) + if not norm or norm in seen: + continue + seen.add(norm) + scored.append(PageCandidate(title=title or norm, url=url, snippet=snippet or "")) + if not scored: + return [] + titles_and_snippets = [f"{c.title} {c.snippet}".strip() for c in scored] + query_emb = self.bundle.embed([query], convert_to_tensor=True)[0] + page_embs = self.bundle.embed(titles_and_snippets, convert_to_tensor=True) + sim_scores = util.cos_sim(query_emb, page_embs)[0] + order = sim_scores.argsort(descending=True).tolist() + ordered = [scored[i] for i in order] + return ordered[:15] + + def fetch_and_extract(self, url: str, page_timeout: int = 20) -> str: + url = self.normalize_url(url) + if not url: + return "" + future = self.executor.submit(self._fetch_and_extract_sync, url) + try: + return future.result(timeout=page_timeout) or "" + except concurrent.futures.TimeoutError: + return "" + except Exception: + return "" + + def _fetch_and_extract_sync(self, url: str) -> str: + try: + r = self.session.get(url, timeout=(8, 15), allow_redirects=True) + r.raise_for_status() + except Exception: + return "" + + content_type = r.headers.get("Content-Type", "").lower() + if "application/pdf" in content_type or url.lower().endswith(".pdf"): + text = self._extract_pdf_bytes(r.content) + return _normalize_whitespace(text) + + html = r.text or "" + text = self.universal_page_parser(url, html, response=r, use_browser=False) + return _normalize_whitespace(text) + + def _extract_pdf_bytes(self, pdf_bytes: bytes) -> str: + try: + with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp: + tmp.write(pdf_bytes) + pdf_path = tmp.name + doc = fitz.open(pdf_path) + text = " ".join(page.get_text() for page in doc) + doc.close() + try: + os.remove(pdf_path) + except Exception: + pass + return text + except Exception: + return "" + + def universal_page_parser(self, url: str, html: str, response=None, use_browser: bool = False) -> str: + text = "" + if YouTubeTranscriptApi is not None and ("youtu" in url.lower()): + video_id = self._extract_youtube_id(url) + if video_id: + try: + transcript = YouTubeTranscriptApi.get_transcript(video_id) + text = " ".join(entry["text"] for entry in transcript).strip() + if text: + return text + except Exception: + pass + if trafilatura is not None: + try: + t = trafilatura.extract(html, include_comments=False, include_tables=True) + if t and len(t.strip()) > 80: + return t.strip() + except Exception: + pass + if extractors is not None: + try: + boilerpy_text = extractors.ArticleExtractor().get_content(html) + if boilerpy_text and len(boilerpy_text.strip()) > 80: + return boilerpy_text.strip() + except Exception: + pass + if Document is not None: + try: + doc = Document(html) + soup = BeautifulSoup(doc.summary(), "html.parser") + text_readability = soup.get_text(" ", strip=True) + if text_readability and len(text_readability.strip()) > 80: + return text_readability.strip() + except Exception: + pass + if Article is not None: + try: + article = Article(url) + article.set_html(html) + article.parse() + text_newspaper = article.text or "" + if text_newspaper and len(text_newspaper.strip()) > 80: + return text_newspaper.strip() + except Exception: + pass + if Goose is not None: + try: + goose_text = Goose().extract(raw_html=html).cleaned_text + if goose_text and len(goose_text.strip()) > 80: + return goose_text.strip() + except Exception: + pass + if inscriptis_text is not None: + try: + inscriptis_parsed = inscriptis_text(html) + if inscriptis_parsed and len(inscriptis_parsed.strip()) > 80: + return inscriptis_parsed.strip() + except Exception: + pass + if lxml_html is not None: + try: + lxml_tree = lxml_html.fromstring(html) + lxml_text = " ".join(lxml_tree.xpath("//p//text()")) + if lxml_text and len(lxml_text.strip()) > 80: + return lxml_text.strip() + except Exception: + pass + try: + soup = BeautifulSoup(html, "html.parser") + for tag in soup(["script", "style", "noscript", "header", "footer", "nav", "aside", "form", "input", "button", "svg", "canvas", "iframe", "object", "embed", "img", "video", "audio"]): + tag.decompose() + tags = ["p", "li", "span", "div", "h1", "h2", "h3", "h4", "h5", "h6"] + bs_text = " ".join(t.get_text(" ", strip=True) for tag in tags for t in soup.find_all(tag)) + if bs_text and len(bs_text.strip()) > 80: + return bs_text.strip() + except Exception: + pass + + try: + soup = BeautifulSoup(html, "html.parser") + for tag in soup(["script", "style", "noscript", "header", "footer", "nav", "aside", "form", "input", "button", "svg", "canvas", "iframe", "object", "embed", "img", "video", "audio"]): + tag.decompose() + visible_text = soup.get_text(" ", strip=True) + if visible_text and len(visible_text.strip()) > 50: + return visible_text.strip() + except Exception: + pass + + return "" + + def _extract_youtube_id(self, url: str) -> Optional[str]: + patterns = [ + r"(?:v=)([A-Za-z0-9_-]{11})", + r"youtu\.be/([A-Za-z0-9_-]{11})", + r"youtube\.com/shorts/([A-Za-z0-9_-]{11})", + r"youtube\.com/embed/([A-Za-z0-9_-]{11})", + ] + for pattern in patterns: + m = re.search(pattern, url) + if m: + return m.group(1) + return None + + def normalize_url(self, url: str) -> str: + if not url: + return "" + + if "resulthunter.com" in url: + qs = parse_qs(urlparse(url).query) + if "url" in qs: + return unquote(qs["url"][0]) + + if url.startswith("/videos/watch/"): + parsed = urlparse(url) + path_parts = parsed.path.split("/") + if len(path_parts) >= 4: + video_id = path_parts[3] + if len(video_id) >= 11: + return f"https://www.youtube.com/watch?v={video_id}" + + if "duckduckgo.com/l/" in url: + qs = parse_qs(urlparse(url).query) + if "uddg" in qs and qs["uddg"]: + return unquote(qs["uddg"][0]) + + return url if url.startswith("http") else f"https://{url.lstrip('/')}" + + def is_ad_link(self, url: str) -> bool: + ad_keywords = ["advert", "ads", "doubleclick", "sponsor", "promo"] + return any(term in (url or "").lower() for term in ad_keywords) + + # ---------------- search engines ---------------- + def duckduckgo_search(self, query: str, num_results: int = 10): + url = "https://html.duckduckgo.com/html/" + data = {"q": query} + try: + r = self.session.post(url, data=data, timeout=(8, 20)) + r.raise_for_status() + except requests.RequestException: + return [] + + soup = BeautifulSoup(r.text, "html.parser") + results = [] + for result in soup.select("div.result"): + title_a = result.select_one("a.result__url") or result.select_one("a.result__a") + snippet_a = result.select_one("a.result__snippet") or result.select_one("div.result__snippet") + if not title_a: + continue + title = title_a.get_text(strip=True) + href = title_a.get("href", "") + if href.startswith("//duckduckgo.com/l/?uddg="): + href = unquote(href.split("uddg=")[1].split("&")[0]) + snippet = snippet_a.get_text(strip=True) if snippet_a else "" + results.append((title, href, snippet)) + if len(results) >= num_results: + break + return results + + def resulthunter_search(self, query: str, num_results: int = 10): + encoded_query = quote(query) + url = f"https://www.resulthunter.com/search?q={encoded_query}" + try: + r = self.session.get(url, timeout=(8, 15)) + r.raise_for_status() + except requests.RequestException: + return [] + + soup = BeautifulSoup(r.text, "html.parser") + results = [] + result_divs = soup.find_all("div", class_="web-result") + if not result_divs: + result_divs = soup.find_all("div", class_=lambda c: c and "result" in c.lower()) + + for result in result_divs: + link_tag = result.find("a", href=True) + if not link_tag: + continue + title = link_tag.get_text(strip=True) + link = link_tag["href"] + if not link.startswith("http"): + continue + snippet_tag = result.find("p", class_="web-result-desc") or result.find("p") + snippet = snippet_tag.get_text(strip=True) if snippet_tag else "" + results.append((title, link, snippet)) + if len(results) >= num_results: + break + return results + + def google_search(self, query: str, num_results: int = 10): + encoded_query = quote(query) + url = f"https://www.google.com/search?q={encoded_query}&num={num_results + 5}" + try: + r = self.session.get(url, timeout=(8, 15)) + r.raise_for_status() + except requests.RequestException: + return [] + + soup = BeautifulSoup(r.text, "html.parser") + results = [] + for g in soup.select("div.g"): + title_el = g.select_one("h3") + link_el = g.select_one("a[href]") + if not (title_el and link_el): + continue + title = title_el.get_text(strip=True) + href = link_el["href"] + snippet_el = g.select_one("div.VwiC3b") + if snippet_el: + snippet = snippet_el.get_text(strip=True) + else: + snippet = g.get_text(separator=" ", strip=True).replace(title, "", 1).strip() + results.append((title, href, snippet)) + if len(results) >= num_results: + break + return results + +def _worker_main(command_queue: Queue, response_queue: Queue): + worker = CrawlWorker() + try: + while True: + msg = command_queue.get() + if not msg: + continue + mtype = msg.get("type") + if mtype == "shutdown": + response_queue.put({"type": "shutdown_ack"}) + break + if mtype != "query": + continue + + req_id = msg["request_id"] + query = msg["query"] + stats = msg.get("stats") + result = worker.run_query(query, stats=stats) + response_queue.put({ + "type": "result", + "request_id": req_id, + "result": result, + }) + finally: + worker.close() + +class WebSearchModule(nn.Module): + def __init__(self, model_dir: str = MODEL_DIR): + super().__init__() + self.model_dir = model_dir + self.bundle = TextModelBundle(model_dir=model_dir) + + self._worker = None + self._command_queue = None + self._response_queue = None + self._worker_ctx = None + self._worker_started = False + + def __getstate__(self): + state = self.__dict__.copy() + state["_worker"] = None + state["_command_queue"] = None + state["_response_queue"] = None + state["_worker_ctx"] = None + state["_worker_started"] = False + return state + + def __setstate__(self, state): + self.__dict__.update(state) + self._worker = None + self._command_queue = None + self._response_queue = None + self._worker_ctx = None + self._worker_started = False + + def _ensure_worker(self): + if self._worker is not None and self._worker.is_alive(): + return + + self._worker_ctx = get_context("spawn") + self._command_queue = self._worker_ctx.Queue() + self._response_queue = self._worker_ctx.Queue() + self._worker = self._worker_ctx.Process( + target=_worker_main, + args=(self._command_queue, self._response_queue), + daemon=True, + ) + self._worker.start() + self._worker_started = True + + def close(self): + if getattr(self, "_worker", None) is None: + return + + try: + if self._worker.is_alive() and self._command_queue is not None: + self._command_queue.put({"type": "shutdown"}) + try: + if self._response_queue is not None: + self._response_queue.get(timeout=10) + except Exception: + pass + self._worker.join(timeout=10) + if self._worker.is_alive(): + self._worker.terminate() + self._worker.join(timeout=5) + finally: + try: + if self._command_queue is not None: + self._command_queue.close() + except Exception: + pass + try: + if self._response_queue is not None: + self._response_queue.close() + except Exception: + pass + self._worker = None + self._command_queue = None + self._response_queue = None + self._worker_ctx = None + self._worker_started = False + + def __del__(self): + try: + self.close() + except Exception: + pass + + def embed(self, texts, convert_to_tensor=True): + return self.bundle.embed(texts, convert_to_tensor=convert_to_tensor) + + def summarize(self, text: str, max_length: int = 300, min_length: int = 50): + return self.bundle.generate_summary(text, max_length=max_length, min_length=min_length) + + def forward(self, query: str, stats: Optional[dict] = None, timeout: Optional[float] = None) -> str: + self._ensure_worker() + + req_id = str(uuid.uuid4()) + if stats is not None: + stats.setdefault("spiders_created", 0) + stats.setdefault("spiders_completed", 0) + stats.setdefault("spiders_killed", 0) + stats.setdefault("total_seconds", 0.0) + stats.setdefault("runs", []) + stats["spiders_created"] += 1 + + self._command_queue.put({ + "type": "query", + "request_id": req_id, + "query": query, + "stats": stats, + }) + + started = time.perf_counter() + effective_timeout = timeout if timeout is not None else None + + while True: + if effective_timeout is not None and (time.perf_counter() - started) > effective_timeout: + return f"Query is still running in the worker process for: {query}" + + try: + msg = self._response_queue.get(timeout=0.25) + except queue.Empty: + continue + except Exception: + continue + + if msg.get("type") != "result" or msg.get("request_id") != req_id: + continue + + result: CrawlResult = msg["result"] + if stats is not None: + stats["spiders_completed"] += 1 + stats["total_seconds"] += result.elapsed_seconds + stats["runs"].append({ + "query": result.query, + "seconds": round(result.elapsed_seconds, 3), + "used_pages": len(result.used_candidates), + "failed_pages": len(result.failed_candidates), + "fallback_used": result.fallback_used, + "error": result.error, + }) + return result.answer or f"No content extracted for query: {query}" + + def __call__(self, query: str, **kwargs): + return self.forward(query, **kwargs) + +class Web: + """ + High-level wrapper around WebSearchModule. + + Features: + - Auto-locates WebSearch.pt in AppData + - Creates one automatically if missing + - Exposes all WebSearchModule methods + - Supports save/load/reload + - Supports direct querying through __call__ + """ + + DEFAULT_FOLDER = os.path.join( + os.getenv("APPDATA", os.path.expanduser("~")), + "PackedLLM" + ) + + DEFAULT_WEB_PATH = os.path.join( + DEFAULT_FOLDER, + "WebSearch.pt" + ) + + def __init__( + self, + web_location: Optional[str] = None, + model_dir: str = "models", + auto_create: bool = True, + ): + self.model_dir = model_dir + + if web_location: + self.web_path = os.path.abspath(web_location) + else: + self.web_path = self.DEFAULT_WEB_PATH + + os.makedirs(os.path.dirname(self.web_path), exist_ok=True) + + if os.path.exists(self.web_path): + self.web = self._load(self.web_path) + + elif auto_create: + self.web = WebSearchModule(model_dir=model_dir) + self.save(self.web_path) + + else: + raise FileNotFoundError( + f"WebSearch checkpoint not found: {self.web_path}" + ) + + def _load(self, path: str) -> WebSearchModule: + obj = torch.load(path, map_location="cpu", weights_only=False) + + if not isinstance(obj, WebSearchModule): + raise TypeError( + f"{path} does not contain a WebSearchModule." + ) + + return obj + + def save(self, path: Optional[str] = None): + target = path or self.web_path + + os.makedirs( + os.path.dirname(os.path.abspath(target)), + exist_ok=True, + ) + + torch.save(self.web, target) + self.web_path = target + + def reload(self): + self.close() + self.web = self._load(self.web_path) + + def search(self, query: str, **kwargs): + return self.web.forward(query, **kwargs) + + def embed(self, texts, convert_to_tensor=True): + return self.web.embed( + texts, + convert_to_tensor=convert_to_tensor, + ) + + def summarize( + self, + text: str, + max_length: int = 300, + min_length: int = 50, + ): + return self.web.summarize( + text, + max_length=max_length, + min_length=min_length, + ) + + def close(self): + try: + self.web.close() + except Exception: + pass + + def __call__(self, query: str, **kwargs): + return self.web(query, **kwargs) + + def __getattr__(self, item): + return getattr(self.web, item) + + @property + def location(self): + return self.web_path + + @property + def exists(self): + return os.path.exists(self.web_path) + + def info(self): + return { + "web_path": self.web_path, + "exists": self.exists, + "worker_running": ( + self.web._worker is not None + and self.web._worker.is_alive() + ), + "model_dir": self.model_dir, + } + + def __repr__(self): + return ( + f"Web(" + f"path='{self.web_path}', " + f"exists={self.exists}" + f")" + ) + +PRIMARY_WEIGHT_FILES = ("pytorch_model.bin") +SKIP_BLOATED_FILES = { + "model.onnx", + "onnx_model.onnx", + "openvino_model.bin", +} + +@staticmethod +def _bytes_to_uint8_tensor(data: bytes) -> torch.Tensor: + arr = np.frombuffer(data, dtype=np.uint8) + return torch.from_numpy(arr.copy()) + +@staticmethod +def _uint8_tensor_to_bytes(t: Union[torch.Tensor, bytes]) -> bytes: + if isinstance(t, bytes): + return t + return bytes(t.detach().cpu().contiguous().numpy().tobytes()) + +@staticmethod +def _pick_primary_weight_file(model_dir: str) -> Optional[str]: + for name in PRIMARY_WEIGHT_FILES: + if os.path.exists(os.path.join(model_dir, name)): + return name + return None + +@dataclass +class PackedRecord: + id: str + text: str + meta: Dict[str, Any] + embedding: Optional[np.ndarray] = None + + +@dataclass +class PackedTreeSnapshot: + version: int + docs_blob: bytes + metas_blob: bytes + ids_blob: bytes + embs_blob: bytes + extra_blob: bytes = b"" + + +class PackedTree: + def __init__(self, name: str, embed_fn: Callable[..., np.ndarray], cluster_k: int = 4): + self.name = name + self.embed_fn = embed_fn + self.cluster_k = int(cluster_k) + + self.docs: List[str] = [] + self.metas: List[Dict[str, Any]] = [] + self.ids: List[str] = [] + self.embs: np.ndarray = np.empty((0, 0), dtype=np.float32) + self.norm_embs: np.ndarray = np.empty((0, 0), dtype=np.float32) + self.id_to_idx: Dict[str, int] = {} + self.hash_to_id: Dict[str, str] = {} + self.query_cache: OrderedDict = OrderedDict() + self.cluster_cache: Dict[str, Any] = {} + self._lock = threading.RLock() + self._clusters_dirty = True + + @staticmethod + def norm_text(text: str) -> str: + return _norm_ws(text).lower() + + @staticmethod + def text_hash(text: str) -> str: + h = hashlib.sha256() + h.update(PackedTree.norm_text(text).encode("utf-8")) + return h.hexdigest() + + def _cache_get(self, key): + v = self.query_cache.get(key) + if v is not None: + self.query_cache.move_to_end(key) + return v + + def _cache_put(self, key, value, max_size: int = 512): + self.query_cache[key] = value + self.query_cache.move_to_end(key) + while len(self.query_cache) > max_size: + self.query_cache.popitem(last=False) + + def add(self, text: str, meta: Optional[Dict[str, Any]] = None, item_id: Optional[str] = None) -> str: + text = _norm_ws(text) + if not text: + return "" + with self._lock: + meta = dict(meta or {}) + item_id = item_id or meta.get("id") or str(uuid.uuid4()) + doc_hash = meta.get("hash") or self.text_hash(text) + if doc_hash in self.hash_to_id: + return self.hash_to_id[doc_hash] + + emb = np.asarray(self.embed_fn(text), dtype=np.float32) + if emb.ndim != 1: + emb = emb.reshape(-1) + + self.id_to_idx[item_id] = len(self.docs) + self.hash_to_id[doc_hash] = item_id + meta.setdefault("id", item_id) + meta.setdefault("hash", doc_hash) + meta.setdefault("timestamp", _now_iso()) + self.docs.append(text) + self.metas.append(meta) + self.ids.append(item_id) + + if self.embs.size == 0: + self.embs = emb.reshape(1, -1).astype(np.float32) + else: + if self.embs.shape[1] != emb.shape[0]: + raise ValueError(f"Embedding dimension mismatch in tree '{self.name}': {emb.shape[0]} != {self.embs.shape[1]}") + self.embs = np.vstack([self.embs, emb.reshape(1, -1)]) + + self.norm_embs = self._normalize_embeddings(self.embs) + self._clusters_dirty = True + return item_id + + def bulk_add(self, items: Sequence[Tuple[str, Dict[str, Any], Optional[str]]]) -> List[str]: + ids = [] + for text, meta, item_id in items: + ids.append(self.add(text, meta=meta, item_id=item_id)) + return ids + + def update_meta(self, item_id: str, patch: Mapping[str, Any]): + with self._lock: + idx = self.id_to_idx.get(item_id) + if idx is None: + return + self.metas[idx].update(dict(patch)) + self._clusters_dirty = True + + def record_usage(self, item_id: str): + with self._lock: + idx = self.id_to_idx.get(item_id) + if idx is None: + return + md = self.metas[idx] + md["usage_count"] = int(md.get("usage_count", 0)) + 1 + md["last_used"] = _now_iso() + + @staticmethod + def _compress(obj: Any) -> bytes: + payload = json.dumps(obj, ensure_ascii=False, default=_json_default).encode("utf-8") + return lzma.compress(payload, preset=9) + + @staticmethod + def _decompress(blob: bytes, default: Any = None) -> Any: + if not blob: + return default + try: + raw = lzma.decompress(blob) + return json.loads(raw.decode("utf-8")) + except Exception: + return default + + def snapshot(self) -> PackedTreeSnapshot: + with self._lock: + docs_blob = self._compress(self.docs) + metas_blob = self._compress(self.metas) + ids_blob = self._compress(self.ids) + embs_blob = lzma.compress(self.embs.astype(np.float16).tobytes(), preset=9) if self.embs.size else b"" + extra = { + "shape": list(self.embs.shape), + "dtype": "float16", + "cluster_k": self.cluster_k, + "hash_to_id": self.hash_to_id, + "id_to_idx": self.id_to_idx, + } + extra_blob = self._compress(extra) + return PackedTreeSnapshot( + version=1, + docs_blob=docs_blob, + metas_blob=metas_blob, + ids_blob=ids_blob, + embs_blob=embs_blob, + extra_blob=extra_blob, + ) + + def restore(self, snap: PackedTreeSnapshot): + with self._lock: + self.docs = self._decompress(snap.docs_blob, default=[]) + self.metas = self._decompress(snap.metas_blob, default=[]) + self.ids = self._decompress(snap.ids_blob, default=[]) + extra = self._decompress(snap.extra_blob, default={}) or {} + shape = tuple(extra.get("shape") or [0, 0]) + self.cluster_k = int(extra.get("cluster_k", self.cluster_k)) + self.hash_to_id = dict(extra.get("hash_to_id", {})) + self.id_to_idx = {k: int(v) for k, v in dict(extra.get("id_to_idx", {})).items()} + + if snap.embs_blob and shape and shape[0] > 0 and shape[1] > 0: + raw = lzma.decompress(snap.embs_blob) + arr = np.frombuffer(raw, dtype=np.float16).reshape(shape).astype(np.float32) + self.embs = arr + self.norm_embs = self._normalize_embeddings(arr) + else: + self.embs = np.empty((0, 0), dtype=np.float32) + self.norm_embs = np.empty((0, 0), dtype=np.float32) + + self.query_cache = OrderedDict() + self.cluster_cache = {} + self._clusters_dirty = True + + @staticmethod + def _normalize_embeddings(embs: np.ndarray) -> np.ndarray: + if embs.size == 0: + return embs + norms = np.linalg.norm(embs, axis=1, keepdims=True) + norms[norms == 0] = 1.0 + return embs / norms + + @staticmethod + def _cosine_scores(query_emb: np.ndarray, matrix: np.ndarray) -> np.ndarray: + if matrix.size == 0: + return np.array([], dtype=np.float32) + q = query_emb.astype(np.float32).reshape(1, -1) + qn = q / np.maximum(np.linalg.norm(q, axis=1, keepdims=True), 1e-8) + mn = PackedTree._normalize_embeddings(matrix.astype(np.float32)) + return (qn @ mn.T)[0] + + def _build_clusters(self): + if KMeans is None or self.embs.shape[0] < 2: + self.cluster_cache = {"centers": None, "clusters": {0: {"idxs": list(range(len(self.docs)))}}} + self._clusters_dirty = False + return + + k = min(self.cluster_k, self.embs.shape[0]) + if k <= 1: + self.cluster_cache = {"centers": self.norm_embs[:1], "clusters": {0: {"idxs": list(range(len(self.docs)))}}} + self._clusters_dirty = False + return + + km = KMeans(n_clusters=k, random_state=0, n_init="auto") + labels = km.fit_predict(self.norm_embs) + centers = km.cluster_centers_.astype(np.float32) + clusters: Dict[int, Dict[str, Any]] = {i: {"idxs": []} for i in range(k)} + for idx, lab in enumerate(labels): + clusters[int(lab)]["idxs"].append(idx) + self.cluster_cache = {"centers": centers, "clusters": clusters} + self._clusters_dirty = False + + def search(self, query: str, top_k: int = 5, min_score: float = 0.0, hybrid: bool = True, use_clusters: bool = False) -> List[Dict[str, Any]]: + query = _norm_ws(query) + if not query: + return [] + qkey = (query, top_k, min_score, hybrid, use_clusters) + cached = self._cache_get(qkey) + if cached is not None: + return cached + + if self.embs.size == 0: + return [] + + q_emb = np.asarray(self.embed_fn(query), dtype=np.float32).reshape(-1) + scores = self._cosine_scores(q_emb, self.embs) + if scores.size == 0: + return [] + + order = np.argsort(scores)[::-1] + results: List[Dict[str, Any]] = [] + seen = set() + q_tokens = set(self.norm_text(query).split()) + + for idx in order: + score = float(scores[idx]) + if score < min_score: + continue + doc = self.docs[int(idx)] + doc_norm = self.norm_text(doc) + if doc_norm in seen: + continue + seen.add(doc_norm) + md = self.metas[int(idx)] + kw = 0.0 + if hybrid and q_tokens: + d_tokens = set(doc_norm.split()) + kw = len(q_tokens.intersection(d_tokens)) / max(1.0, (len(q_tokens) + len(d_tokens)) / 2.0) + final = 0.75 * score + 0.2 * kw + 0.05 * float(md.get("importance", 0.5)) + results.append({ + "id": self.ids[int(idx)], + "passage": doc, + "raw_similarity": score, + "score": max(0.0, min(1.0, final)), + "metadata": md, + }) + if len(results) >= top_k: + break + + if use_clusters and self._clusters_dirty: + self._build_clusters() + + self._cache_put(qkey, results) + return results + + def retrieve_by_semantics(self, query: str, num_clusters: int = 2, top_k_per_cluster: int = 3, min_score: float = 0.0) -> List[Dict[str, Any]]: + query = _norm_ws(query) + if not query: + return [] + if self.embs.size == 0: + return [] + if self._clusters_dirty: + self._build_clusters() + + centers = self.cluster_cache.get("centers") + clusters = self.cluster_cache.get("clusters") or {} + if centers is None: + return self.search(query, top_k=num_clusters * top_k_per_cluster, min_score=min_score, hybrid=True) + + q_emb = np.asarray(self.embed_fn(query), dtype=np.float32).reshape(1, -1) + center_sims = self._cosine_scores(q_emb.reshape(-1), centers) + top_cluster_ids = np.argsort(center_sims)[::-1][:min(num_clusters, len(center_sims))] + results: List[Dict[str, Any]] = [] + seen = set() + + for cid in top_cluster_ids: + idxs = clusters.get(int(cid), {}).get("idxs", []) + if not idxs: + continue + local_embs = self.norm_embs[idxs] + sims = self._cosine_scores(q_emb.reshape(-1), local_embs) + top_local = np.argsort(sims)[::-1][:top_k_per_cluster] + for local_idx in top_local: + global_idx = idxs[int(local_idx)] + raw = float(sims[int(local_idx)]) + if raw < min_score: + continue + doc = self.docs[global_idx] + doc_norm = self.norm_text(doc) + if doc_norm in seen: + continue + seen.add(doc_norm) + md = self.metas[global_idx] + q_tokens = set(self.norm_text(query).split()) + d_tokens = set(doc_norm.split()) + kw = len(q_tokens.intersection(d_tokens)) / max(1.0, (len(q_tokens) + len(d_tokens)) / 2.0) + final = 0.75 * raw + 0.2 * kw + 0.05 * float(md.get("importance", 0.5)) + results.append({ + "id": self.ids[global_idx], + "passage": doc, + "raw_similarity": raw, + "score": max(0.0, min(1.0, final)), + "metadata": md, + }) + if len(results) >= top_k_per_cluster * num_clusters: + break + if len(results) < top_k_per_cluster: + extra = self.search(query, top_k=top_k_per_cluster * num_clusters, min_score=min_score, hybrid=True) + for item in extra: + if self.norm_text(item["passage"]) not in seen: + seen.add(self.norm_text(item["passage"])) + results.append(item) + return results + + +def _json_default(obj: Any): + if isinstance(obj, (np.integer, np.floating)): + return obj.item() + if isinstance(obj, np.ndarray): + return obj.tolist() + if isinstance(obj, (set, tuple)): + return list(obj) + if dataclasses.is_dataclass(obj): + return asdict(obj) + if isinstance(obj, bytes): + return base64.b64encode(obj).decode("ascii") + if isinstance(obj, Path): + return str(obj) + raise TypeError(f"Object of type {type(obj).__name__} is not JSON serializable") + + +def _extract_response_text_from_result(result: Any) -> str: + def coerce_to_str(v): + if isinstance(v, str): + return v + if isinstance(v, (list, tuple)): + pieces = [] + for x in v: + if isinstance(x, str) and x.strip(): + pieces.append(x) + elif isinstance(x, dict): + for k in ("content", "response", "assistant", "final"): + if k in x and isinstance(x[k], str) and x[k].strip(): + pieces.append(x[k]) + break + else: + for val in x.values(): + if isinstance(val, str) and val.strip(): + pieces.append(val) + else: + try: + pieces.append(str(x)) + except Exception: + pass + return "\n".join(pieces) + if isinstance(v, dict): + for key in ("response", "assistant", "final", "content"): + val = v.get(key) + if isinstance(val, str) and val.strip(): + return val + if isinstance(val, (list, tuple, dict)): + s = coerce_to_str(val) + if s: + return s + vals = [str(x) for x in v.values() if isinstance(x, str) and x.strip()] + if vals: + return "\n".join(vals) + try: + return json.dumps(v) + except Exception: + return str(v) + try: + return str(v) + except Exception: + return "" + + if isinstance(result, dict): + for key in ("blocks", "response", "assistant", "final", "content"): + if key in result and result[key]: + return coerce_to_str(result[key]) + vals = [v for v in result.values() if isinstance(v, (str, list, dict)) and v] + if vals: + return coerce_to_str(vals[0]) + return json.dumps(result) + return coerce_to_str(result) + + +class DesktopControl: + def __init__(self): + self._available = None + + def _lazy_import(self): + if self._available is not None: + return self._available + mods = {} + for name in ("pyautogui", "keyboard", "mouse", "psutil", "win32gui", "pygetwindow", "ctypes"): + try: + mods[name] = importlib.import_module(name) + except Exception: + mods[name] = None + self._available = mods + return mods + + def get_location_string(self) -> str: + try: + import geocoder # type: ignore + g = geocoder.ip("me") + city = g.city or "UnknownCity" + state = g.state or "UnknownState" + country = g.country or "UnknownCountry" + return f"{city}/{state}/{country}" + except Exception: + return "UnknownCity/UnknownState/UnknownCountry" + + def get_time_string(self) -> str: + now = datetime.now() + date_str = now.strftime("%d/%m/%Y") + time_str = now.strftime("%I:%M:%S/%p").lower() + return f"{date_str}\n{time_str}" + + def is_desktop_active(self) -> bool: + mods = self._lazy_import() + win32gui = mods.get("win32gui") + if win32gui is None: + return False + desktop_hwnd = win32gui.GetDesktopWindow() + active_hwnd = win32gui.GetForegroundWindow() + return active_hwnd == desktop_hwnd + + def is_program_active(self, program_name: str) -> bool: + mods = self._lazy_import() + gw = mods.get("pygetwindow") + psutil_mod = mods.get("psutil") + if gw is None or psutil_mod is None: + return False + active_window = gw.getActiveWindow() + if active_window: + active_title = active_window.title or "" + for process in psutil_mod.process_iter(["pid", "name"]): + name = (process.info.get("name") or "").lower() + if name == program_name.lower(): + return program_name.lower() in active_title.lower() + return False + + def fast_move(self, x, y): + mods = self._lazy_import() + if mods.get("ctypes") is None: + return + mods["ctypes"].windll.user32.SetCursorPos(x, y) + + def scroll_mouse(self, delta): + mods = self._lazy_import() + if mods.get("ctypes") is None: + return + mods["ctypes"].windll.user32.mouse_event(0x0800, 0, 0, int(delta * 120), 0) + + def press_special_key(self, key): + mods = self._lazy_import() + if mods.get("ctypes") is None: + return + special_keys = { + "volume up": 0xAF, + "volume down": 0xAE, + "volume mute": 0xAD, + "play/pause media": 0xB3, + "next track": 0xB0, + "prev track": 0xB1, + } + vk_code = special_keys.get(key) + if vk_code is None: + return + mods["ctypes"].windll.user32.keybd_event(vk_code, 0, 0, 0) + mods["ctypes"].windll.user32.keybd_event(vk_code, 0, 2, 0) + time.sleep(0.1) + + def minimize_all_windows(self): + mods = self._lazy_import() + if mods.get("ctypes") is None: + return + mods["ctypes"].windll.user32.keybd_event(0x5B, 0, 0, 0) + mods["ctypes"].windll.user32.keybd_event(0x4D, 0, 0, 0) + mods["ctypes"].windll.user32.keybd_event(0x4D, 0, 2, 0) + mods["ctypes"].windll.user32.keybd_event(0x5B, 0, 2, 0) + time.sleep(1) + + def run_pyautogui_command(self, command_name: str): + mods = self._lazy_import() + pyautogui = mods.get("pyautogui") + if pyautogui is None: + raise RuntimeError("pyautogui is not installed") + getattr(pyautogui, command_name)() + + +@dataclass +class ActionDecision: + type: str + command_name: Optional[str] = None + command_description: Optional[str] = None + command_text: Optional[str] = None + memory_access: List[str] = field(default_factory=list) + source: Optional[str] = None + profile: Optional[str] = None + query: Optional[str] = None + sufficient_to_answer: bool = False + parameters: Dict[str, Any] = field(default_factory=dict) + + +class CommandRegistry: + def __init__(self, owner: "GATOR"): + self.owner = owner + self.commands: Dict[str, Dict[str, Any]] = {} + self.custom_commands: Dict[str, Dict[str, Any]] = {} + self.shortcuts_dir = "./Mods/COMMANDS" + self._lock = threading.RLock() + + def register_command(self, name: str, description: str, action: Optional[Callable] = None, command_type: str = "basic"): + with self._lock: + self.commands[name] = { + "name": name, + "description": description, + "action": action, + "type": command_type, + } + + def update_command(self, name: str, description: Optional[str] = None, action: Optional[Callable] = None, command_type: Optional[str] = None): + with self._lock: + if name not in self.commands: + self.commands[name] = {"name": name, "description": "", "action": None, "type": "basic"} + if description is not None: + self.commands[name]["description"] = description + if action is not None: + self.commands[name]["action"] = action + if command_type is not None: + self.commands[name]["type"] = command_type + + def register_custom_command(self, command_name: str, phrase: str, description: str, actions: Optional[List[Dict[str, Any]]] = None): + with self._lock: + self.custom_commands[command_name] = { + "phrase": phrase, + "description": description, + "actions": actions or [], + } + self.owner.command_tree.add_command_branch( + command_name=phrase, + command_action=command_name, + command_type="custom", + description=description, + ) + + def check_custom_commands(self, text: str, matched_commands: Optional[List[str]] = None): + matched_commands = matched_commands or [] + text_lower = (text or "").lower() + for command_name, data in self.custom_commands.items(): + phrase = (data.get("phrase") or "").lower() + if phrase and phrase in text_lower: + matched_commands.append(command_name) + return matched_commands if matched_commands else False + + def check_basic_commands(self, text: str, matched_commands: Optional[List[Tuple[Callable, List[Any]]]] = None): + matched_commands = matched_commands or [] + text_lower = (text or "").lower() + for command_dict in self.commands.values(): + commands = command_dict.get("commands") or [command_dict.get("name")] + action = command_dict.get("action") + if action is None: + continue + for cmd in commands: + if cmd and cmd.lower() in text_lower: + matched_commands.append((action, [])) + return bool(matched_commands) + + def check_shortcuts(self, text: str, shortcut_dir: Optional[str] = None): + shortcut_dir = shortcut_dir or self.shortcuts_dir + os.makedirs(shortcut_dir, exist_ok=True) + actions = [] + text_lower = (text or "").lower() + for entry in os.listdir(shortcut_dir): + entry_path = os.path.join(shortcut_dir, entry) + if os.path.isdir(entry_path): + actions.extend(self._check_folder(entry_path, text_lower)) + else: + name_no_ext = os.path.splitext(entry)[0].lower() + if os.path.isfile(entry_path) and name_no_ext in text_lower: + actions.append((os.startfile, [entry_path])) + return actions + + def _check_folder(self, base_dir, text_lower): + matched_paths = [] + for entry in os.listdir(base_dir): + entry_path = os.path.join(base_dir, entry) + name_no_ext = os.path.splitext(entry)[0].lower() + if os.path.isfile(entry_path) and name_no_ext in text_lower: + matched_paths.append(entry_path) + elif os.path.isdir(entry_path): + matched_paths.extend(self._check_folder(entry_path, text_lower)) + return [(os.startfile, [p]) for p in matched_paths] + + def execute_command(self, commands, command_executed_tags, argument_dictionary=None): + for action, _ in commands: + map_args = [] + if argument_dictionary: + map_args = [] + for arg in []: + if isinstance(arg, str) and arg.startswith("{") and arg.endswith("}"): + key = arg.strip("{}") + map_args.append(argument_dictionary.get(key, "")) + else: + map_args.append(arg) + action(*map_args) + command_executed_tags.append(f"Executed action: {getattr(action, '__name__', str(action))}") + + def execute_shortcut(self, actions, command_executed_tags): + for action_fn, args in actions: + file_path = os.path.abspath(args[0]) + if not os.path.exists(file_path): + command_executed_tags.append(f"Path not found: {file_path}") + continue + if os.path.isdir(file_path): + command_executed_tags.append(f"Skipped directory: {file_path}") + continue + try: + os.startfile(file_path) + command_executed_tags.append(f"Opened: {file_path}") + except Exception: + try: + subprocess.Popen(["cmd", "/c", "start", "", file_path], shell=True) + command_executed_tags.append(f"Opened via cmd start: {file_path}") + except Exception: + command_executed_tags.append(f"Failed to open: {file_path}") + + def execute_custom_command(self, command_name): + payload = self.custom_commands.get(command_name) + if not payload: + return + actions = payload.get("actions") or [] + if not actions: + return + for action in actions: + kind = action.get("event") + if kind == "key_down": + self.owner.desktop._lazy_import().get("pyautogui") + import pyautogui # type: ignore + pyautogui.keyDown(action["key"]) + elif kind == "key_up": + import pyautogui # type: ignore + pyautogui.keyUp(action["key"]) + elif kind == "mouse_down": + import pyautogui # type: ignore + pyautogui.mouseDown(button=action["button"]) + elif kind == "mouse_up": + import pyautogui # type: ignore + pyautogui.mouseUp(button=action["button"]) + elif kind == "mouse_move": + self.owner.desktop.fast_move(action["x"], action["y"]) + elif kind == "mouse_scroll": + self.owner.desktop.scroll_mouse(action["delta"]) + + def process_commands(self, command, command_type="shortcut", argument_dictionary=None): + command_executed_tags = [] + executed_actions = [] + + if command_type == "basic": + basic_matches = [] + if self.check_basic_commands(command, basic_matches): + self.execute_command(basic_matches, command_executed_tags, argument_dictionary) + executed_actions.extend(basic_matches) + + elif command_type == "shortcut": + shortcut_actions = self.check_shortcuts(command, self.shortcuts_dir) + if shortcut_actions: + self.execute_shortcut(shortcut_actions, command_executed_tags) + executed_actions.extend(shortcut_actions) + + elif command_type == "custom": + found = self.check_custom_commands(command) + if found: + for cmd_name in found: + self.execute_custom_command(cmd_name) + executed_actions.append(cmd_name) + + return executed_actions + + +# --------------------------------------------------------------------------- +# GATOR module +# --------------------------------------------------------------------------- +class GATOR(nn.Module): + + STATE_VERSION = 1 + + def __init__( + self, + lm_checkpoint_path: str = "LM.pt", + embedder_name: str = "second-state/jina-embeddings-v3-GGUF", + embedder_local_dir: str = os.path.join("models", "jinaai"), + embedder_filename: str = GGUF_EMBED_FILENAME, + device: str = "cpu", + warm_on_start: bool = True, + compression: str = "lzma", + store_dtype: str = "float16", + cluster_k: int = 4, + auto_load_lm: bool = True, + strict_lm: bool = True, + embedder_pack: Optional[Dict[str, Any]] = None, + ): + super().__init__() + + self.config = { + "lm_checkpoint_path": lm_checkpoint_path, + "embedder_name": embedder_name, + "embedder_local_dir": embedder_local_dir, + "embedder_filename": embedder_filename, + "device": device, + "warm_on_start": warm_on_start, + "compression": compression, + "store_dtype": store_dtype, + "cluster_k": cluster_k, + "auto_load_lm": auto_load_lm, + "strict_lm": strict_lm, + } + + self.device_name = device + self.compression = compression + self.store_dtype = store_dtype + self.cluster_k = int(cluster_k) + self.strict_lm = strict_lm + self._lock = threading.RLock() + self._snapshot_cache: Dict[str, bytes] = {} + self._runtime_cache: OrderedDict = OrderedDict() + self._runtime_cache_max = 16 + self._last_route: Dict[str, Any] = {} + self._last_response: str = "" + self._last_plan: Dict[str, Any] = {} + + self.desktop = DesktopControl() + self.command_registry = CommandRegistry(self) + self.lm = self._load_lm(lm_checkpoint_path, auto_load=auto_load_lm) + + self.embedder_name = embedder_name + self.embedder_local_dir = embedder_local_dir + self.embedder_filename = embedder_filename + + if embedder_pack is not None and embedder_pack.get("gguf_bytes") is not None: + self.embedder_pack = embedder_pack + self.embedder = self._restore_embedder_from_pack(self.embedder_pack) + self.embedder_path = self.embedder_pack.get("gguf_source_path", "") + else: + self.embedder_path = self._resolve_local_embedder_gguf(embedder_local_dir, embedder_filename) + self.embedder_pack = self._load_embedder_pack(self.embedder_path) + self.embedder = self._restore_embedder_from_pack(self.embedder_pack) + + self.embedder_tokenizer = None + probe = self._embed_raw(["__gator_probe__"], task="retrieval.passage") + self.embed_dim = int(probe.shape[-1]) if probe.ndim == 2 and probe.shape[-1] > 0 else 1024 + + self._store: Dict[str, PackedTree] = { + "knowledge": PackedTree("knowledge", self.embed, cluster_k=self.cluster_k), + "conversation": PackedTree("conversation", self.embed, cluster_k=self.cluster_k), + "profile_user": PackedTree("profile_user", self.embed, cluster_k=self.cluster_k), + "profile_bot": PackedTree("profile_bot", self.embed, cluster_k=self.cluster_k), + "commands": PackedTree("commands", self.embed, cluster_k=self.cluster_k), + "assets": PackedTree("assets", self.embed, cluster_k=self.cluster_k), + "telemetry": PackedTree("telemetry", self.embed, cluster_k=self.cluster_k), + } + + self._command_phrases: Dict[str, Dict[str, Any]] = {} + self._warm_on_start = warm_on_start + if warm_on_start: + self.warmup() + + @staticmethod + def _bytes_to_uint8_tensor(data: bytes) -> torch.Tensor: + arr = np.frombuffer(data, dtype=np.uint8) + return torch.from_numpy(arr.copy()) + + @staticmethod + def _uint8_tensor_to_bytes(t: torch.Tensor) -> bytes: + return bytes(t.detach().cpu().contiguous().numpy().tobytes()) + + def __getstate__(self): + state = self.__dict__.copy() + state["embedder"] = None + state["embedder_tokenizer"] = None + state["embedder_pack"] = self._snapshot_embedder_pack() + state["lm"] = self._snapshot_lm_handle() + state["_lock"] = None + return state + + def __setstate__(self, state): + self.__dict__.update(state) + self._lock = threading.RLock() + self.desktop = self.desktop if isinstance(self.desktop, DesktopControl) else DesktopControl() + self.command_registry = self.command_registry if isinstance(self.command_registry, CommandRegistry) else CommandRegistry(self) + if self.embedder is None: + self.embedder = self._restore_embedder_from_pack(self.embedder_pack) + self.embedder_tokenizer = None + self.lm = self._restore_lm_handle(self.lm) + if not hasattr(self, "_store"): + self._store = { + "knowledge": PackedTree("knowledge", self.embed, cluster_k=self.cluster_k), + "conversation": PackedTree("conversation", self.embed, cluster_k=self.cluster_k), + "profile_user": PackedTree("profile_user", self.embed, cluster_k=self.cluster_k), + "profile_bot": PackedTree("profile_bot", self.embed, cluster_k=self.cluster_k), + "commands": PackedTree("commands", self.embed, cluster_k=self.cluster_k), + "assets": PackedTree("assets", self.embed, cluster_k=self.cluster_k), + "telemetry": PackedTree("telemetry", self.embed, cluster_k=self.cluster_k), + } + + def _load_lm(self, lm_checkpoint_path: str, auto_load: bool = True): + if not auto_load: + return None + if load_packedlm is None: + raise RuntimeError("PackedLM.load_packedlm is unavailable. Import PackedLM before GATOR.") + if not os.path.exists(lm_checkpoint_path): + raise FileNotFoundError(f"LM checkpoint not found: {lm_checkpoint_path}") + return load_packedlm(lm_checkpoint_path) + + def _snapshot_lm_handle(self): + return self.lm + + def _restore_lm_handle(self, packed): + return packed + + def _resolve_local_embedder_gguf(self, local_dir: str, embedder_filename: str) -> str: + candidates = [ + Path(local_dir).resolve() if local_dir else None, + Path("models").resolve(), + (Path("models") / "jinaai").resolve(), + (Path("models") / "jinaai" / "jina-embeddings-v3").resolve(), + ] + candidates = [p for p in candidates if p is not None] + + for root in candidates: + if not root.exists(): + continue + + direct = root / embedder_filename + if direct.is_file(): + return str(direct) + + for p in root.rglob(embedder_filename): + if p.is_file(): + return str(p) + + raise FileNotFoundError( + f"Could not find {embedder_filename} under: {[str(p) for p in candidates]}" + ) + + def _load_embedder_pack(self, gguf_path: str) -> Dict[str, Any]: + pack_path = str(Path(gguf_path).with_suffix(Path(gguf_path).suffix + ".pt")) + + if os.path.exists(pack_path): + try: + pack = torch.load(pack_path, map_location="cpu", weights_only=False) + if isinstance(pack, dict) and pack.get("gguf_bytes") is not None: + return pack + except Exception: + try: + os.remove(pack_path) + except Exception: + pass + + raw = Path(gguf_path).read_bytes() + pack = { + "gguf_filename": Path(gguf_path).name, + "gguf_bytes": self._bytes_to_uint8_tensor(raw), + "gguf_source_path": str(Path(gguf_path).resolve()), + } + + try: + torch.save(pack, pack_path, pickle_protocol=5) + except Exception: + pass + + return pack + + def _restore_embedder_from_pack(self, pack: Dict[str, Any]): + if not pack or pack.get("gguf_bytes") is None: + raise RuntimeError("Embedder GGUF pack is missing") + + tmp_dir = tempfile.mkdtemp(prefix="gator_embedder_") + try: + gguf_path = Path(tmp_dir) / pack["gguf_filename"] + gguf_path.write_bytes(self._uint8_tensor_to_bytes(pack["gguf_bytes"])) + + llm = Llama( + model_path=str(gguf_path), + embedding=True, + verbose=False, + n_ctx=8192, + use_mmap=False, + use_mlock=False, + ) + return llm + finally: + shutil.rmtree(tmp_dir, ignore_errors=True) + + def _load_embedder(self, model_name: str, local_dir: str): + gguf_path = self._resolve_local_embedder_gguf(local_dir, self.embedder_filename) + pack = self._load_embedder_pack(gguf_path) + embedder = self._restore_embedder_from_pack(pack) + return embedder, None, pack + + def _snapshot_embedder_pack(self) -> Dict[str, Any]: + if isinstance(self.embedder_pack, dict) and self.embedder_pack.get("gguf_bytes") is not None: + return { + "gguf_filename": self.embedder_pack["gguf_filename"], + "gguf_bytes": self.embedder_pack["gguf_bytes"], + "gguf_source_path": self.embedder_pack.get("gguf_source_path", ""), + } + raise RuntimeError("Embedder pack is missing") + + def _embed_raw(self, texts: Union[str, Sequence[str]], task: str = "retrieval.passage") -> np.ndarray: + if isinstance(texts, str): + texts = [texts] + if not texts: + return np.empty((0, self.embed_dim), dtype=np.float32) + + if hasattr(self.embedder, "create_embedding"): + resp = self.embedder.create_embedding(list(texts)) + if isinstance(resp, dict) and "data" in resp: + embs = [row["embedding"] for row in resp["data"]] + else: + embs = resp + elif hasattr(self.embedder, "embed"): + resp = self.embedder.embed(list(texts)) + if isinstance(resp, dict) and "data" in resp: + embs = [row["embedding"] for row in resp["data"]] + else: + embs = resp + else: + raise RuntimeError("Loaded GGUF embedder does not expose create_embedding() or embed()") + + embs = np.asarray(embs, dtype=np.float32) + if embs.ndim == 1: + embs = embs.reshape(1, -1) + return embs + + def embed(self, texts: Union[str, Sequence[str]], task: str = "retrieval.passage") -> np.ndarray: + return self._embed_raw(texts, task=task) + + def embed_query(self, texts: Union[str, Sequence[str]]) -> np.ndarray: + return self.embed(texts, task="retrieval.query") + + def embed_passage(self, texts: Union[str, Sequence[str]]) -> np.ndarray: + return self.embed(texts, task="retrieval.passage") + + def embed_classification(self, texts: Union[str, Sequence[str]]) -> np.ndarray: + return self.embed(texts, task="classification") + + def embed_matching(self, texts: Union[str, Sequence[str]]) -> np.ndarray: + return self.embed(texts, task="text-matching") + + def _snapshot_store(self) -> Dict[str, Any]: + return {name: tree.snapshot() for name, tree in self._store.items()} + + def _restore_store(self, packed: Mapping[str, Any]): + for name, tree in self._store.items(): + snap = packed.get(name) + if isinstance(snap, PackedTreeSnapshot): + tree.restore(snap) + elif isinstance(snap, dict): + tree.restore(PackedTreeSnapshot(**snap)) + + @staticmethod + def normalize_for_hash(obj: Any) -> Any: + if isinstance(obj, dict): + return {k: GATOR.normalize_for_hash(v) for k, v in obj.items()} + if isinstance(obj, list): + return [GATOR.normalize_for_hash(v) for v in obj] + if hasattr(obj, "item"): + try: + return obj.item() + except Exception: + return obj + return obj + + def get_location_string(self): + return self.desktop.get_location_string() + + def get_time_string(self): + return self.desktop.get_time_string() + + def _lm_head(self, prompt: str, mode: str = "decision") -> Dict[str, Any]: + if self.lm is None: + raise RuntimeError("LM.pt is not loaded") + system_prompt = ( + "You are GATOR HeadExpert. Decide whether the user request needs retrieval, a tool, or a direct answer. " + "Return strict JSON only." + ) + tool_prompt = { + "input_text": prompt, + "available_commands": list(self.command_registry.commands.values()), + "system_goal": system_prompt, + "mode": mode, + } + if hasattr(self.lm, "head_expert"): + raw = self.lm.head_expert(_safe_json_dumps(tool_prompt)) + else: + raw = self.lm.head(prompt) + return self._parse_json_object(raw, default={"actions": []}) + + def _lm_tool(self, query: str, tools: List[Dict[str, Any]]) -> Dict[str, Any]: + if self.lm is None: + raise RuntimeError("LM.pt is not loaded") + if hasattr(self.lm, "tool_expert"): + raw = self.lm.tool_expert(query, tools=tools) + else: + raw = self.lm.tool(query, tools=tools) + return self._parse_json_object(raw, default={"tool_calls": []}) + + @staticmethod + def _parse_json_object(text: str, default: Any = None) -> Any: + if not text: + return default + text = text.strip() + try: + return json.loads(text) + except Exception: + m = re.search(r"(\{.*})", text, re.DOTALL) + if m: + try: + return json.loads(m.group(1)) + except Exception: + return default + return default + + def _decision_to_actions(self, decision: Mapping[str, Any]) -> List[ActionDecision]: + actions = decision.get("actions") if isinstance(decision, Mapping) else None + if not isinstance(actions, list): + actions = [decision] if isinstance(decision, Mapping) else [] + parsed: List[ActionDecision] = [] + for item in actions: + if not isinstance(item, Mapping): + continue + parsed.append(ActionDecision( + type=str(item.get("type", "None")), + command_name=item.get("command_name"), + command_description=item.get("command_description"), + command_text=item.get("command_text"), + memory_access=list(item.get("memory_access") or []), + source=item.get("source"), + profile=item.get("profile"), + query=item.get("query"), + sufficient_to_answer=bool(item.get("sufficient_to_answer", False)), + parameters=dict(item.get("parameters") or {}), + )) + return parsed + + def store_knowledge(self, documents: Sequence[str], tags: Optional[Sequence[str]] = None, source: str = "user", importance: float = 0.5): + tags = list(tags) if tags is not None else ["knowledge"] * len(documents) + if len(tags) != len(documents): + raise ValueError("Length of tags must match length of documents") + for doc, tag in zip(documents, tags): + meta = {"tag": tag, "source": source, "importance": float(importance), "usage_count": 0, "last_used": None} + self._store["knowledge"].add(doc, meta) + + def search_knowledge(self, query: str, top_k: int = 5, hybrid: bool = True, min_score: float = 0.0): + return self._store["knowledge"].search(query, top_k=top_k, hybrid=hybrid, min_score=min_score, use_clusters=True) + + def process_knowledge(self, query, history="", location="", time_date=""): + if not query: + return [] + try: + results = self._store["knowledge"].retrieve_by_semantics(query=query, num_clusters=3, top_k_per_cluster=3, min_score=0.0) + except Exception: + results = self._store["knowledge"].search(query=query, top_k=9, hybrid=True) + return results + + def store_conversation_leaf(self, text: str, conv_id: str, leaf_type: str = "input"): + meta = {"id": conv_id, "type": "branch", "leaf_type": leaf_type} + self._store["conversation"].add(text, meta) + + def process_conversation(self, query, id, type="input"): + if type == "input": + relevant_context = self.conversation_tree.add_input_leaf(query, id) + return relevant_context + else: + self.conversation_tree.add_output_leaf(query, id) + + def store_profile_leaf(self, profile_id: str, text: str, importance: float = 0.5, profile_type: str = "user"): + target = "profile_user" if profile_type == "user" else "profile_bot" + meta = {"profile_id": profile_id, "importance": float(importance), "source": profile_type} + self._store[target].add(text, meta) + + def search_profile_leaves(self, profile_id: str, query: str, profile_type: str = "user", top_k: int = 3, min_score: float = 0.0): + target = "profile_user" if profile_type == "user" else "profile_bot" + tree = self._store[target] + results = tree.search(query, top_k=max(top_k * 3, top_k), min_score=min_score, hybrid=True, use_clusters=True) + filtered = [r for r in results if r.get("metadata", {}).get("profile_id") == profile_id] + return filtered[:top_k] + + def store_command( + self, + command_name: str, + phrase: str, + description: str, + command_type: str = "custom", + actions: Optional[List[Dict[str, Any]]] = None + ): + meta = { + "command_name": command_name, + "phrase": phrase, + "description": description, + "type": command_type, + "actions": actions or [], + } + + self.command_registry.custom_commands[command_name] = meta + self.command_registry.commands[command_name] = meta + + self._store["commands"].add( + f"Command: {phrase}", + { + "command_name": command_name, + "phrase": phrase, + "description": description, + "type": command_type, + }, + item_id=f"command::{command_type}::{command_name}", + ) + def search_commands(self, query: str, top_k: int = 3): + return self._store["commands"].search(query, top_k=top_k, hybrid=True) + + def execute_retrieval_action(self, action, user_id, bot_id, history="", location="", time_date=""): + source = action.get("source") + profile = action.get("profile") + query = action.get("query") + if not query: + return None + if source == "KnowledgeTree": + return self.process_knowledge(query=query, history=history, location=location, time_date=time_date) + if source == "ProfileTree": + if profile == "user_profile": + return self.search_profile_leaves(user_id, query, profile_type="user") + if profile == "bot_profile": + return self.search_profile_leaves(bot_id, query, profile_type="bot") + return None + + def _merge_retrieval_actions(self, actions: List[ActionDecision]) -> Dict[str, List[Dict[str, Any]]]: + retrieval_actions = [a for a in actions if a.type == "retrieval"] + if not retrieval_actions: + return {"KnowledgeTree": [], "ProfileTree": []} + out = {"KnowledgeTree": [], "ProfileTree": []} + for a in retrieval_actions: + if a.source == "KnowledgeTree" or (a.memory_access and "KnowledgeTree" in a.memory_access): + out["KnowledgeTree"].append(asdict(a)) + if a.source == "ProfileTree" or (a.memory_access and "ProfileTree" in a.memory_access): + out["ProfileTree"].append(asdict(a)) + return out + + def process_actions(self, query, user_id, bot_id, history="", location="", time_date=""): + relevant_commands = self.search_commands(query, top_k=3) + available_actions = [ + { + "name": c["metadata"].get("command_name", c["id"]), + "description": c["metadata"].get("description", ""), + "type": c["metadata"].get("type", "command"), + } + for c in relevant_commands + ] + + decision_prompt = { + "query": query, + "available_commands": available_actions, + "history": history, + "location": location, + "time_date": time_date, + "user_id": user_id, + "bot_id": bot_id, + "route_goal": "Use HeadExpert to decide whether retrieval is needed. If a tool/command is needed, choose it with ToolExpert.", + } + + head_decision = self._lm_head(_safe_json_dumps(decision_prompt), mode="decision") + actions = self._decision_to_actions(head_decision) + self._last_plan = head_decision if isinstance(head_decision, dict) else {} + + command_needed = any(a.type == "command" for a in actions) + retrieval_needed = any(a.type == "retrieval" for a in actions) + + if not actions: + actions = [ActionDecision(type="None", sufficient_to_answer=True)] + + matched_commands: List[Any] = [] + retrieved_data: Dict[str, List[Any]] = {} + + if retrieval_needed: + for action in actions: + if action.type != "retrieval": + continue + if action.sufficient_to_answer: + continue + result = self.execute_retrieval_action(asdict(action), user_id, bot_id, history=history, location=location, time_date=time_date) + if result is None: + continue + source = action.source or "KnowledgeTree" + retrieved_data.setdefault(source, []) + if isinstance(result, list): + retrieved_data[source].extend(result) + else: + retrieved_data[source].append(result) + + if command_needed: + tool_calls = self._lm_tool( + query, + tools=available_actions, + ) + for call in tool_calls.get("tool_calls", []): + if not isinstance(call, dict): + continue + command_name = call.get("name") or call.get("command_name") + parameters = call.get("arguments") or call.get("parameters") or {} + cmd_meta = next((cmd for cmd in relevant_commands if cmd["metadata"].get("command_name") == command_name), None) + if cmd_meta: + command_type = cmd_meta["metadata"].get("type", "custom") + matched = self.command_registry.process_commands(command_name, command_type, parameters) + matched_commands.extend(matched) + + shortcut_matches = self.command_registry.process_commands(query, "shortcut") + matched_commands.extend(shortcut_matches) + + final_commands = " ".join([str(m) for m in matched_commands]) if matched_commands else None + for key, values in retrieved_data.items(): + seen = set() + deduped = [] + for v in values: + try: + normalized = self.normalize_for_hash(v) + h = _safe_json_dumps(normalized) + except Exception: + h = str(v) + if h not in seen: + seen.add(h) + deduped.append(v) + retrieved_data[key] = deduped + + self._last_route = {"commands": final_commands, "retrieved_data": retrieved_data, "head_plan": head_decision} + return {"commands": final_commands, "retrieved_data": retrieved_data} + + def warmup(self): + try: + _ = self.embed(["__gator_warmup__"], task="retrieval.passage") + except Exception: + pass + + def export_snapshot_bytes(self) -> bytes: + payload = { + "version": self.STATE_VERSION, + "config": self.config, + "embedder_pack": self._snapshot_embedder_pack(), + "stores": self._snapshot_store(), + "command_phrases": self._command_phrases, + "custom_commands": self.command_registry.custom_commands, + "commands": self.command_registry.commands, + "last_route": self._last_route, + "last_response": self._last_response, + "last_plan": self._last_plan, + } + buf = io.BytesIO() + torch.save(payload, buf) + return lzma.compress(buf.getvalue(), preset=9) + + def import_snapshot_bytes(self, blob: bytes): + payload = torch.load(io.BytesIO(lzma.decompress(blob)), map_location="cpu", weights_only=False) + self._restore_store(payload.get("stores", {})) + self.command_registry.custom_commands = payload.get("custom_commands", {}) or {} + self.command_registry.commands = payload.get("commands", {}) or {} + self._command_phrases = payload.get("command_phrases", {}) or {} + self._last_route = payload.get("last_route", {}) or {} + self._last_response = payload.get("last_response", "") or "" + self._last_plan = payload.get("last_plan", {}) or {} + if payload.get("embedder_pack"): + self.embedder_pack = payload["embedder_pack"] + self.embedder, self.embedder_tokenizer, self.embedder_pack = self._restore_embedder_from_pack(self.embedder_pack) + self.embedder_local_dir = self.embedder_pack.get("local_dir", self.embedder_local_dir) + + def save_checkpoint(self, path: str = "GATOR.pt") -> None: + self.warmup() + payload = { + "version": self.STATE_VERSION, + "config": self.config, + "embedder_pack": self._snapshot_embedder_pack(), + "stores": self._snapshot_store(), + "custom_commands": self.command_registry.custom_commands, + "commands": self.command_registry.commands, + "command_phrases": self._command_phrases, + "last_route": self._last_route, + "last_response": self._last_response, + "last_plan": self._last_plan, + } + torch.save(payload, path, pickle_protocol=5) + + @classmethod + def load_checkpoint(cls, path: str = "GATOR.pt") -> "GATOR": + if not os.path.exists(path): + raise FileNotFoundError(path) + + payload = torch.load(path, map_location="cpu", weights_only=False) + cfg = payload.get("config", {}) + + obj = cls( + lm_checkpoint_path=cfg.get("lm_checkpoint_path", "LM.pt"), + embedder_name=cfg.get("embedder_name", "second-state/jina-embeddings-v3-GGUF"), + embedder_local_dir=cfg.get("embedder_local_dir", os.path.join("models", "jinaai")), + embedder_filename=cfg.get("embedder_filename", GGUF_EMBED_FILENAME), + device=cfg.get("device", "cpu"), + warm_on_start=False, + compression=cfg.get("compression", "lzma"), + store_dtype=cfg.get("store_dtype", "float16"), + cluster_k=int(cfg.get("cluster_k", 4)), + auto_load_lm=bool(cfg.get("auto_load_lm", True)), + strict_lm=bool(cfg.get("strict_lm", True)), + embedder_pack=payload.get("embedder_pack"), + ) + + obj._restore_store(payload.get("stores", {})) + obj.command_registry.custom_commands = payload.get("custom_commands", {}) or {} + obj.command_registry.commands = payload.get("commands", {}) or {} + obj._command_phrases = payload.get("command_phrases", {}) or {} + obj._last_route = payload.get("last_route", {}) or {} + obj._last_response = payload.get("last_response", "") or "" + obj._last_plan = payload.get("last_plan", {}) or {} + + if payload.get("embedder_pack"): + obj.embedder_pack = payload["embedder_pack"] + obj.embedder = obj._restore_embedder_from_pack(obj.embedder_pack) + + return obj + + def infer_actions(self, prompt: str) -> Dict[str, Any]: + return self._lm_head(prompt, mode="decision") + + def infer_command(self, prompt_payload: Dict[str, Any]) -> Dict[str, Any]: + tools = prompt_payload.get("available_commands", []) + query = prompt_payload.get("input_text", "") + return self._lm_tool(query, tools=tools) + + def respond(self, query: str, user_id: str, bot_id: str, history: str = "", location: str = "", time_date: str = ""): + routed = self.process_actions(query, user_id=user_id, bot_id=bot_id, history=history, location=location, time_date=time_date) + return routed + + def process_command(self, *args, **kwargs): + return self.process_actions(*args, **kwargs) + + def summary(self) -> Dict[str, Any]: + return { + "config": dict(self.config), + "stores": {name: {"count": len(tree.docs), "dim": int(tree.embs.shape[1]) if tree.embs.size else self.embed_dim} for name, tree in self._store.items()}, + "commands": len(self.command_registry.commands), + "custom_commands": len(self.command_registry.custom_commands), + "last_route": self._last_route, + "last_plan": self._last_plan, + } + + def run_self_test(self) -> Dict[str, Any]: + report = {} + try: + report["embed"] = tuple(self.embed(["hello world"], task="retrieval.passage").shape) + except Exception as e: + report["embed_error"] = repr(e) + + try: + self.store_knowledge(["The capital of France is Paris."], tags=["fact"], source="test", importance=1.0) + report["knowledge"] = self.search_knowledge("What is the capital of France?", top_k=1) + except Exception as e: + report["knowledge_error"] = repr(e) + + try: + self.store_profile_leaf("user-1", "Likes Japanese food.", importance=0.8, profile_type="user") + report["profile"] = self.search_profile_leaves("user-1", "food preference", profile_type="user", top_k=1) + except Exception as e: + report["profile_error"] = repr(e) + + try: + self.store_command("test_cmd", "test command", "A small test command", command_type="custom", actions=[]) + report["commands"] = self.search_commands("test command", top_k=1) + except Exception as e: + report["commands_error"] = repr(e) + + return {"report": report, "summary": self.summary()} + + @property + def profile_tree(self): + return types.SimpleNamespace(search_leaves=lambda profile_id, query, top_k=3, min_score=0.0, use_clusters=True: self.search_profile_leaves(profile_id, query, profile_type="user", top_k=top_k, min_score=min_score)) + + @property + def conversation_tree(self): + return types.SimpleNamespace( + add_input_leaf=lambda text, id: self._store["conversation"].search(text, top_k=3, hybrid=True, use_clusters=True), + add_output_leaf=lambda text, id: self.store_conversation_leaf(text, id, leaf_type="output"), + ) + + @property + def knowledge_tree(self): + return types.SimpleNamespace( + retrieve_by_semantics=lambda query, num_clusters=2, top_k_per_cluster=3, min_score=0.0: self._store["knowledge"].retrieve_by_semantics(query, num_clusters=num_clusters, top_k_per_cluster=top_k_per_cluster, min_score=min_score), + search=lambda query, top_k=5, hybrid=True: self._store["knowledge"].search(query, top_k=top_k, hybrid=hybrid), + _embed_text=lambda text: self.embed(text, task="retrieval.passage")[0], + _warm_collection=lambda: self.warmup(), + ) + + @property + def command_tree(self): + return types.SimpleNamespace( + search_relevant_commands=lambda query, top_k=3: self.search_commands(query, top_k=top_k), + add_command_branch=lambda command_name, command_action, command_type, description: self.store_command(command_action, command_name, description, command_type=command_type), + update_command_description=lambda command_name, new_description: self.command_registry.update_command(command_name, description=new_description), + ) + + def save(self, path: str = "GATOR.pt"): + return self.save_checkpoint(path) + + def __repr__(self) -> str: + return f"GATOR(embedder={self.embedder_name!r}, local_dir={self.embedder_local_dir!r}, stores={list(self._store.keys())}, commands={len(self.command_registry.commands)})" + +class MemoryBank: + """ + Thin owner/wrapper around GATOR. + + - Loads an existing GATOR.pt if present. + - Builds a new one if missing. + - Uses AppData/LocalAppData as the default location when no path is passed. + - Delegates all unknown attributes/methods directly to the underlying GATOR instance. + """ + + DEFAULT_APP_FOLDER = "PackedLLM" + DEFAULT_BUNDLE_NAME = "GATOR.pt" + + def __init__( + self, + gator_location: Optional[Union[str, os.PathLike]] = None, + *, + build_if_missing: bool = True, + **gator_kwargs: Any, + ): + self.root_dir = self._resolve_root_dir(gator_location) + self.root_dir.mkdir(parents=True, exist_ok=True) + + self.checkpoint_path = self._resolve_checkpoint_path(self.root_dir) + + if self.checkpoint_path.exists(): + self.gator = GATOR.load_checkpoint(str(self.checkpoint_path)) + else: + if not build_if_missing: + raise FileNotFoundError(f"No GATOR checkpoint found at: {self.checkpoint_path}") + + self.gator = GATOR(**gator_kwargs) + self.gator.save_checkpoint(str(self.checkpoint_path)) + + @classmethod + def _default_appdata_dir(cls) -> Path: + local_appdata = os.getenv("LOCALAPPDATA") + appdata = os.getenv("APPDATA") + + if local_appdata: + base = Path(local_appdata) + elif appdata: + base = Path(appdata) + else: + base = Path.home() / "AppData" / "Local" + + return base / cls.DEFAULT_APP_FOLDER + + @classmethod + def _resolve_root_dir(cls, gator_location: Optional[Union[str, os.PathLike]]) -> Path: + if gator_location is None: + return cls._default_appdata_dir() + path = Path(gator_location).expanduser().resolve() + if path.suffix.lower() == ".pt": + return path.parent + + return path + + @classmethod + def _resolve_checkpoint_path(cls, root_dir: Path) -> Path: + return root_dir / cls.DEFAULT_BUNDLE_NAME + + def save(self) -> str: + self.root_dir.mkdir(parents=True, exist_ok=True) + self.gator.save_checkpoint(str(self.checkpoint_path)) + return str(self.checkpoint_path) + + def reload(self) -> None: + if not self.checkpoint_path.exists(): + raise FileNotFoundError(str(self.checkpoint_path)) + self.gator = GATOR.load_checkpoint(str(self.checkpoint_path)) + + def rebuild(self, **gator_kwargs: Any) -> None: + self.gator = GATOR(**gator_kwargs) + self.gator.save_checkpoint(str(self.checkpoint_path)) + + def __getattr__(self, name: str) -> Any: + return getattr(self.gator, name) + + def __dir__(self): + base = set(super().__dir__()) + try: + base.update(dir(self.gator)) + except Exception: + pass + return sorted(base) + + def __repr__(self) -> str: + return f"MemoryBank(root_dir={str(self.root_dir)!r}, checkpoint_path={str(self.checkpoint_path)!r})" + +class HardwareProbe: + @staticmethod + def cpu() -> Dict[str, Any]: + physical = psutil.cpu_count(logical=False) or psutil.cpu_count(logical=True) or 1 + logical = psutil.cpu_count(logical=True) or physical + vm = psutil.virtual_memory() + return { + "physical_cores": physical, + "logical_cores": logical, + "available_ram_gb": vm.available / (1024 ** 3), + "total_ram_gb": vm.total / (1024 ** 3), + } + + @staticmethod + def nvidia_gpu() -> Optional[Dict[str, Any]]: + try: + cmd = ( + "nvidia-smi --query-gpu=name,memory.total,memory.free,memory.used," + "utilization.gpu --format=csv,noheader,nounits" + ) + out = subprocess.check_output(cmd.split(), stderr=subprocess.DEVNULL).decode("ascii").strip() + if not out: + return None + parts = [p.strip() for p in out.split(",")] + return { + "backend": "cuda", + "device_name": parts[0], + "total_vram_gb": float(parts[1]) / 1024.0, + "free_vram_gb": float(parts[2]) / 1024.0, + "used_vram_gb": float(parts[3]) / 1024.0, + "utilization_pct": float(parts[4]), + } + except Exception: + return None + + @staticmethod + def torch_gpu() -> Optional[Dict[str, Any]]: + try: + if torch.cuda.is_available(): + idx = torch.cuda.current_device() + free_b, total_b = torch.cuda.mem_get_info(idx) + return { + "backend": "cuda", + "device_name": torch.cuda.get_device_name(idx), + "total_vram_gb": total_b / (1024 ** 3), + "free_vram_gb": free_b / (1024 ** 3), + "used_vram_gb": (total_b - free_b) / (1024 ** 3), + "utilization_pct": None, + } + except Exception: + pass + + try: + if getattr(torch.backends, "mps", None) is not None and torch.backends.mps.is_available(): + vm = psutil.virtual_memory() + return { + "backend": "metal", + "device_name": "Apple Silicon (MPS)", + "total_vram_gb": vm.total / (1024 ** 3), + "free_vram_gb": vm.available / (1024 ** 3), + "used_vram_gb": (vm.total - vm.available) / (1024 ** 3), + "utilization_pct": None, + } + except Exception: + pass + return None + + @staticmethod + def webgpu() -> Optional[Dict[str, Any]]: + if not _WGPU_AVAILABLE: + return None + try: + request = getattr(wgpu.gpu, "request_adapter_sync", None) or getattr(wgpu.gpu, "request_adapter") + adapter = request(power_preference="high-performance") + limits = getattr(adapter, "limits", {}) or {} + max_buffer_bytes = limits.get("max-buffer-size") or limits.get("maxBufferSize") or 0 + est_gb = (max_buffer_bytes / (1024 ** 3)) * 0.5 if max_buffer_bytes else 1.0 + return { + "backend": "webgpu", + "device_name": getattr(adapter, "summary", "WebGPU adapter"), + "total_vram_gb": est_gb, + "free_vram_gb": est_gb, + "used_vram_gb": 0.0, + "utilization_pct": None, + } + except Exception: + return None + + @classmethod + def snapshot(cls) -> Dict[str, Any]: + gpu = cls.nvidia_gpu() or cls.torch_gpu() + webgpu = None if gpu is not None else cls.webgpu() + return {"cpu": cls.cpu(), "gpu": gpu, "webgpu": webgpu} + + +@dataclass +class RunMetrics: + duration_sec: float + tokens: int + tokens_per_sec: float + template_used: Optional[str] + offload_plan: Dict[str, Any] + telemetry_deltas: Dict[str, Any] + timestamp: float = field(default_factory=time.time) + +class ExpertHandle(nn.Module): + def __init__(self, name: str, spec: Dict[str, Any]): + super().__init__() + self.name = name + self.spec: Dict[str, Any] = dict(spec) + self._llama = None + self.last_prompt: str = "" + self.last_response: str = "" + self.last_template_used: Optional[str] = None + self.last_offload_plan: Dict[str, Any] = {} + self.last_metrics: Dict[str, Any] = {} + self.metrics_history: List[Dict[str, Any]] = [] + self.call_count: int = 0 + self.total_inference_sec: float = 0.0 + self.avg_inference_sec: float = 0.0 + self.total_tokens_generated: int = 0 + self.avg_tokens_per_sec: float = 0.0 + self.load_time_sec: Optional[float] = None + + def __getstate__(self): + state = self.__dict__.copy() + + if self.name == "TranslationExpert" and isinstance(state.get("_llama"), dict): + m_data = state["_llama"] + model = m_data.get("model") + + state["_llama"] = { + "state_dict": model.state_dict(), + "config": model.config, + "tokenizer": m_data.get("tokenizer"), + "local_dir": m_data.get("local_dir") + } + elif self.name != "TranslationExpert": + state["_llama"] = None + + return state + + def __setstate__(self, state): + self.__dict__.update(state) + + if self.name == "TranslationExpert" and isinstance(self._llama, dict) and "state_dict" in self._llama: + from transformers import MarianMTModel + + data = self._llama + model = MarianMTModel(data["config"]) + model.load_state_dict(data["state_dict"]) + + self._llama = { + "tokenizer": data["tokenizer"], + "model": model, + "local_dir": data["local_dir"] + } + + def is_loaded(self) -> bool: + return self._llama is not None + + def record_run( + self, + prompt_repr: str, + response: str, + duration_sec: float, + tokens: int, + telemetry_deltas: Dict[str, Any], + template_used: Optional[str] = None, + ) -> None: + self.last_prompt = prompt_repr + self.last_response = response + self.last_template_used = template_used + self.call_count += 1 + self.total_inference_sec += duration_sec + self.avg_inference_sec = self.total_inference_sec / self.call_count + self.total_tokens_generated += tokens + tps = (tokens / duration_sec) if duration_sec > 0 else 0.0 + self.avg_tokens_per_sec = ((self.avg_tokens_per_sec * (self.call_count - 1)) + tps) / self.call_count + entry = asdict( + RunMetrics( + duration_sec=duration_sec, + tokens=tokens, + tokens_per_sec=tps, + template_used=template_used, + offload_plan=self.last_offload_plan, + telemetry_deltas=telemetry_deltas, + ) + ) + self.last_metrics = entry + self.metrics_history.append(entry) + if len(self.metrics_history) > 25: + self.metrics_history.pop(0) + + def forward(self, *args, **kwargs): # pragma: no cover + raise RuntimeError(f"ExpertHandle('{self.name}') is not directly callable.") + + +# ================================================================ +# PackedLM +# ================================================================ + +class PackedLM(nn.ModuleDict): + DEFAULT_LAYER_GUESS = 32 + VRAM_SAFETY_MARGIN = 1.15 + WEBGPU_SAFETY_MARGIN = 1.40 + + _R1_USER_TOKEN = "<|User|>" + _R1_ASSISTANT_TOKEN = "<|Assistant|>" + + _XLAM_TASK_INSTRUCTION_DEFAULT = ( + "Based on the user's query, decide whether a function call is needed and, if so, " + "produce the correct call(s) using only the tools provided." + ) + _XLAM_FORMAT_INSTRUCTION_DEFAULT = ( + 'Generate a JSON object of the form {"tool_calls": [{"name": "func_name", ' + '"arguments": {"arg1": "value1"}}, ...]}. If no function call is needed, ' + 'return {"tool_calls": []}. Output JSON only, nothing else.' + ) + + def __init__(self, bundle_path: Optional[str] = DEFAULT_BUNDLE_PATH, auto_load_bundle: bool = True): + super().__init__() + self.bundle_path = bundle_path + self.bundle: Optional[Dict[str, Any]] = None + self.last_expert: str = "" + self._embed_tempfiles: Dict[str, str] = {} + self._hf_translation_dir = str(DEFAULT_ZH_EN_DIR) + + if auto_load_bundle and bundle_path and os.path.exists(bundle_path): + self.load_bundle(bundle_path) + + def __getstate__(self): + state = self.__dict__.copy() + for name, expert in self.items(): + if name == "TranslationExpert": + continue + + if hasattr(expert, "_llama"): + expert._llama = None + return state + + def load_bundle(self, bundle_path: str) -> "PackedLM": + self.bundle_path = bundle_path + self.bundle = torch.load(bundle_path, map_location="cpu", weights_only=False) + models = self.bundle.get("models", {}) + for name, spec in models.items(): + self[name] = ExpertHandle(name, spec) + # Optional translation module for zh->en support. + if "TranslationExpert" not in self and "zh_en_translator" not in self: + self["TranslationExpert"] = ExpertHandle( + "TranslationExpert", + { + "kind": "hf_seq2seq", + "repo_id": ZH_EN_REPO_ID, + "local_dir": self._hf_translation_dir, + "source_lang": "zh", + "target_lang": "en", + }, + ) + return self + + def reload_expert(self, expert_name: str) -> "PackedLM": + if expert_name not in self: + raise KeyError(f"Unknown expert '{expert_name}'. Loaded experts: {list(self.keys())}") + expert = self[expert_name] + if expert.spec.get("kind") == "hf_seq2seq": + self._load_translation_backend(force_reload=True) + return self + expert._llama = None + self._get_llama(expert, force_reload=True) + return self + + def unload_expert(self, expert_name: str) -> None: + if expert_name in self and hasattr(self[expert_name], "_llama"): + self[expert_name]._llama = None + + def unload_all(self) -> None: + for name in list(self.keys()): + self.unload_expert(name) + + def summary(self) -> Dict[str, Any]: + out: Dict[str, Any] = {} + for name, expert in self.items(): + out[name] = { + "loaded": expert.is_loaded(), + "call_count": expert.call_count, + "avg_inference_sec": round(expert.avg_inference_sec, 4), + "avg_tokens_per_sec": round(expert.avg_tokens_per_sec, 2), + "last_offload_plan": expert.last_offload_plan, + "last_response_preview": (expert.last_response[:160] + "...") if len(expert.last_response) > 160 else expert.last_response, + } + out["_last_expert"] = self.last_expert + return out + + @staticmethod + def _tensor_to_bytes(t: Any) -> bytes: + if isinstance(t, bytes): + return t + if torch.is_tensor(t): + return bytes(t.detach().cpu().contiguous().numpy().tobytes()) + raise TypeError(f"Unsupported embedded asset type: {type(t)}") + + def _resolve_model_path(self, expert: ExpertHandle) -> str: + spec = expert.spec + path = spec.get("path", "") + if path and os.path.exists(path): + return path + + assets = (self.bundle or {}).get("assets", {}).get("gguf", {}) + embedded = assets.get(expert.name) + if embedded is None: + raise FileNotFoundError(f"Model '{expert.name}' has no external path and no embedded GGUF bytes in the bundle.") + + cache_key = expert.name + if cache_key in self._embed_tempfiles and os.path.exists(self._embed_tempfiles[cache_key]): + return self._embed_tempfiles[cache_key] + + raw = self._tensor_to_bytes(embedded) + tmp = tempfile.NamedTemporaryFile(prefix=f"{expert.name}_", suffix=".gguf", delete=False) + tmp.write(raw) + tmp.flush() + tmp.close() + self._embed_tempfiles[cache_key] = tmp.name + return tmp.name + + def _resolve_projector_path(self, expert: ExpertHandle) -> Optional[str]: + spec = expert.spec + path = spec.get("mmproj_path") or spec.get("clip_model_path") or spec.get("clip_path") + if not path: + return None + if os.path.exists(path): + return path + + assets = (self.bundle or {}).get("assets", {}).get("gguf", {}) + embedded = assets.get(path) + if embedded is None: + return None + + cache_key = f"{expert.name}_mmproj" + if cache_key in self._embed_tempfiles and os.path.exists(self._embed_tempfiles[cache_key]): + return self._embed_tempfiles[cache_key] + + raw = self._tensor_to_bytes(embedded) + tmp = tempfile.NamedTemporaryFile(prefix=f"{expert.name}_mmproj_", suffix=".gguf", delete=False) + tmp.write(raw) + tmp.flush() + tmp.close() + self._embed_tempfiles[cache_key] = tmp.name + return tmp.name + + def _plan_offload(self, expert: ExpertHandle) -> Dict[str, Any]: + hw = HardwareProbe.snapshot() + spec = expert.spec + try: + model_path = self._resolve_model_path(expert) + file_size_gb = os.path.getsize(model_path) / (1024 ** 3) + except Exception: + file_size_gb = float(spec.get("approx_size_gb", 2.0)) + + n_layers = int(spec.get("n_layers", self.DEFAULT_LAYER_GUESS)) + reasoning: List[str] = [] + + if hw["gpu"] is not None: + gpu = hw["gpu"] + needed = file_size_gb * self.VRAM_SAFETY_MARGIN + if gpu["free_vram_gb"] >= needed: + n_gpu_layers = -1 + reasoning.append(f"{gpu['backend']} GPU '{gpu['device_name']}' has {gpu['free_vram_gb']:.2f}GB free >= {needed:.2f}GB needed -> full offload") + else: + frac = max(0.0, gpu["free_vram_gb"] / needed) if needed > 0 else 0.0 + n_gpu_layers = max(0, int(frac * n_layers)) + reasoning.append(f"{gpu['backend']} GPU has only {gpu['free_vram_gb']:.2f}GB free of {needed:.2f}GB needed -> partial offload of {n_gpu_layers}/{n_layers} layers") + backend = gpu["backend"] + elif hw["webgpu"] is not None: + webgpu = hw["webgpu"] + needed = file_size_gb * self.WEBGPU_SAFETY_MARGIN + if webgpu["free_vram_gb"] >= needed: + n_gpu_layers = -1 + reasoning.append("WebGPU adapter's estimated budget covers the full model -> full offload") + else: + frac = max(0.0, webgpu["free_vram_gb"] / needed) if needed > 0 else 0.0 + n_gpu_layers = max(0, int(frac * n_layers)) + reasoning.append(f"WebGPU adapter budget covers ~{frac * 100:.0f}% of the model -> partial offload of {n_gpu_layers}/{n_layers} layers") + backend = "webgpu" + else: + n_gpu_layers = 0 + backend = "cpu" + reasoning.append("No CUDA/Metal GPU or WebGPU adapter detected -> CPU-only") + + n_threads = max(1, hw["cpu"]["physical_cores"] - 1) + return { + "backend": backend, + "n_gpu_layers": n_gpu_layers, + "n_threads": n_threads, + "model_size_gb": round(file_size_gb, 3), + "hardware_snapshot": hw, + "rationale": " | ".join(reasoning), + } + + def _get_llama(self, expert: ExpertHandle, force_reload: bool = False): + if expert.is_loaded() and not force_reload: + return expert._llama + if not _LLAMA_CPP_AVAILABLE: + raise RuntimeError("llama-cpp-python is not installed.") + + model_path = self._resolve_model_path(expert) + plan = self._plan_offload(expert) + + chat_handler = None + if expert.spec.get("vision", False): + projector_path = self._resolve_projector_path(expert) + if projector_path: + from llama_cpp.llama_chat_format import Qwen25VLChatHandler + chat_handler = Qwen25VLChatHandler(clip_model_path=projector_path) + + t0 = time.perf_counter() + llama = Llama( + model_path=model_path, + n_ctx=expert.spec.get("ctx", 8192), + n_threads=plan["n_threads"], + n_gpu_layers=plan["n_gpu_layers"], + chat_handler=chat_handler, + verbose=False, + ) + expert.load_time_sec = time.perf_counter() - t0 + expert.last_offload_plan = plan + expert._llama = llama + return llama + + def _load_translation_backend(self): + if "TranslationExpert" not in self: + raise RuntimeError("TranslationExpert not found.") + + expert = self["TranslationExpert"] + + if isinstance(expert._llama, dict) and "model" in expert._llama: + return expert._llama + + if self.bundle and "assets" in self.bundle and "translation" in self.bundle["assets"]: + print("Hydrating TranslationExpert from embedded bundle assets...") + from transformers import MarianMTModel, MarianTokenizer, MarianConfig + import tempfile + import shutil + + asset_data = self.bundle["assets"]["translation"] + + tok_tmp = Path(tempfile.mkdtemp(prefix="zh_en_tok_")) + try: + for filename, filebytes in asset_data["tokenizer_files"].items(): + target_path = tok_tmp / filename + target_path.parent.mkdir(parents=True, exist_ok=True) + target_path.write_bytes(filebytes) + tokenizer = MarianTokenizer.from_pretrained(str(tok_tmp)) + finally: + shutil.rmtree(tok_tmp, ignore_errors=True) + + config = MarianConfig.from_dict(asset_data["config"]) + model = MarianMTModel(config) + model.load_state_dict(asset_data["state_dict"]) + + expert._llama = { + "tokenizer": tokenizer, + "model": model, + "local_dir": self._hf_translation_dir + } + return expert._llama + + raise RuntimeError("Translation model data not found or corrupted in bundle assets.") + + def _translate_with_internal_model(self, text: str) -> str: + backend = self._load_translation_backend() + tokenizer = backend["tokenizer"] + model = backend["model"] + + inputs = tokenizer(text, return_tensors="pt", truncation=True) + + inputs = {k: v.to(model.device) for k, v in inputs.items()} + + with torch.no_grad(): + generated = model.generate(**inputs, max_new_tokens=128, renormalize_logits=True, repetition_penalty=1.1,) + + return tokenizer.batch_decode(generated, skip_special_tokens=True)[0].strip() + + def translate_zh_en(self, text: str, template: Optional[Union[str, Callable]] = None) -> str: + del template # reserved for future parity with the other experts + if not text: + return "" + if not CHINESE_RE.search(text): + return text + return self._translate_with_internal_model(text) + + def _translate_chinese_spans(self, text: str) -> str: + if not CHINESE_RE.search(text): + return text + + def repl(match: re.Match) -> str: + segment = match.group(0).strip() + if not segment: + return segment + try: + translated = self.translate_zh_en(segment) + return translated if translated else segment + except Exception: + return segment + + return CHINESE_SPAN_RE.sub(repl, text) + + @staticmethod + def _is_url(value: str) -> bool: + try: + return urlparse(value).scheme in ("http", "https") + except Exception: + return False + + @staticmethod + def _image_to_data_uri(image_path: str, max_pixels: int = 1_000_000) -> str: + if not _PIL_AVAILABLE: + raise RuntimeError("Pillow is required for local image encoding.") + with Image.open(image_path) as img: + if img.mode not in ("RGB", "RGBA"): + img = img.convert("RGB") + width, height = img.size + if width * height > max_pixels: + scale = (max_pixels / (width * height)) ** 0.5 + img = img.resize((int(width * scale), int(height * scale)), Image.Resampling.LANCZOS) + buffer = io.BytesIO() + img.save(buffer, format="PNG") + b64 = base64.b64encode(buffer.getvalue()).decode("utf-8") + return f"data:image/png;base64,{b64}" + + @staticmethod + def _build_messages( + template: Optional[Union[str, list, Callable]], + prompt: str, + default_builder: Callable[..., List[Dict[str, Any]]], + **fields: Any, + ) -> List[Dict[str, Any]]: + if template is None: + return default_builder(prompt, **fields) + if callable(template) and not isinstance(template, (str, list)): + return template(prompt, **fields) + if isinstance(template, list): + return template + if isinstance(template, str): + base = default_builder(prompt, **fields) + content = template.format(prompt=prompt, **fields) + if base and base[0].get("role") == "system": + return [base[0], {"role": "user", "content": content}] + return [{"role": "user", "content": content}] + raise TypeError("template must be None, a list[dict], a callable, or a str") + + def _exec_chat(self, expert_name: str, messages: List[Dict[str, Any]], max_tokens: int, temperature: float, **gen_kwargs): + expert = self[expert_name] + llama = self._get_llama(expert) + t_pre = capture_telemetry() + t0 = time.perf_counter() + out = llama.create_chat_completion(messages=messages, max_tokens=max_tokens, temperature=temperature, **gen_kwargs) + dt = time.perf_counter() - t0 + t_post = capture_telemetry() + text = out["choices"][0]["message"]["content"] + tokens = out.get("usage", {}).get("completion_tokens", 0) + deltas = calculate_delta(t_pre, t_post) + return text, tokens, dt, deltas + + def _exec_completion(self, expert_name: str, raw_prompt: str, max_tokens: int, temperature: float, stop: Optional[List[str]] = None, **gen_kwargs): + expert = self[expert_name] + llama = self._get_llama(expert) + t_pre = capture_telemetry() + t0 = time.perf_counter() + out = llama.create_completion(prompt=raw_prompt, max_tokens=max_tokens, temperature=temperature, stop=stop, **gen_kwargs) + dt = time.perf_counter() - t0 + t_post = capture_telemetry() + text = out["choices"][0]["text"] + tokens = out.get("usage", {}).get("completion_tokens", 0) + deltas = calculate_delta(t_pre, t_post) + return text, tokens, dt, deltas + + def _finalize(self, expert_name: str, prompt_repr: str, final_text: str, duration_sec: float, tokens: int, telemetry_deltas: Dict[str, Any], template_used: Optional[str]) -> str: + expert = self[expert_name] + expert.record_run(prompt_repr=prompt_repr, response=final_text, duration_sec=duration_sec, tokens=tokens, telemetry_deltas=telemetry_deltas, template_used=template_used) + self.last_expert = expert_name + return final_text + + def _default_creative_messages(self, prompt: str, tone: Optional[str] = None, length: Optional[str] = None, pov: Optional[str] = None, style: Optional[str] = None) -> List[Dict[str, Any]]: + system = "You are a creative writing assistant." + if tone: + system += f" Match this tone: {tone}." + constraints = [c for c in (f"length: {length}" if length else None, f"POV: {pov}" if pov else None, f"style: {style}" if style else None) if c] + user = prompt + ("\n\nConstraints: " + ", ".join(constraints) if constraints else "") + return [{"role": "system", "content": system}, {"role": "user", "content": user}] + + def creative_expert(self, prompt: str, tone: Optional[str] = None, length: Optional[str] = None, pov: Optional[str] = None, style: Optional[str] = None, template: Optional[Union[str, list, Callable]] = None, max_tokens: int = 600, temperature: float = 0.9, **gen_kwargs) -> str: + messages = self._build_messages(template, prompt, self._default_creative_messages, tone=tone, length=length, pov=pov, style=style) + text, tokens, dt, deltas = self._exec_chat("CreativeExpert", messages, max_tokens, temperature, **gen_kwargs) + return self._finalize("CreativeExpert", prompt, text, dt, tokens, deltas, "custom" if template is not None else "default") + + def _default_code_messages(self, prompt: str, language: Optional[str] = None, context: Optional[str] = None, constraints: Optional[str] = None) -> List[Dict[str, Any]]: + parts = [f"Task: {prompt}"] + if language: + parts.append(f"Language: {language}") + if context: + parts.append(f"Context:\n{context}") + if constraints: + parts.append(f"Constraints:\n{constraints}") + return [{"role": "user", "content": "\n".join(parts)}] + + def code_expert(self, prompt: str, language: Optional[str] = None, context: Optional[str] = None, constraints: Optional[str] = None, template: Optional[Union[str, list, Callable]] = None, max_tokens: int = 1200, temperature: float = 0.2, **gen_kwargs) -> str: + messages = self._build_messages(template, prompt, self._default_code_messages, language=language, context=context, constraints=constraints) + text, tokens, dt, deltas = self._exec_chat("CodeExpert", messages, max_tokens, temperature, **gen_kwargs) + return self._finalize("CodeExpert", prompt, text, dt, tokens, deltas, "custom" if template is not None else "default") + + def _logic_default_raw(self, prompt: str, mode: str): + instruction = prompt.strip() + if mode == "deep_then_answer": + instruction += "\nPlease reason step by step, then provide the final answer succinctly." + raw = f"{self._R1_USER_TOKEN}{instruction}{self._R1_ASSISTANT_TOKEN}" + return raw, None, lambda t: t.strip() + if mode == "think_only": + instruction += "\nPlease reason step by step, and do not provide a final answer." + raw = f"{self._R1_USER_TOKEN}{instruction}{self._R1_ASSISTANT_TOKEN}\n" + return raw, [""], lambda t: "\n" + t.strip() + "\n" + if mode == "skip_reasoning": + raw = f"{self._R1_USER_TOKEN}{prompt.strip()}{self._R1_ASSISTANT_TOKEN}\n\n\n\n" + return raw, None, lambda t: t.strip() + raise ValueError(f"Unknown LogicExpert mode: {mode!r}") + + def logic_expert(self, prompt: str, mode: str = "deep_then_answer", template: Optional[Union[str, Callable]] = None, max_tokens: int = 1024, temperature: float = 0.6, **gen_kwargs) -> str: + if mode not in ("deep_then_answer", "skip_reasoning", "think_only"): + raise ValueError("mode must be one of: deep_then_answer, skip_reasoning, think_only") + + if template is not None: + stop = gen_kwargs.pop("stop", None) + raw_prompt = template(prompt, mode) if callable(template) else str(template).format(prompt=prompt, mode=mode) + wrap = lambda t: t + else: + raw_prompt, stop, wrap = self._logic_default_raw(prompt, mode) + + raw_text, tokens, dt, deltas = self._exec_completion("LogicExpert", raw_prompt, max_tokens, temperature, stop=stop, **gen_kwargs) + final_text = wrap(raw_text) + return self._finalize("LogicExpert", prompt, final_text, dt, tokens, deltas, "custom" if template is not None else mode) + + def _default_role_messages(self, prompt: str, character_card: Optional[str] = None) -> List[Dict[str, Any]]: + system = character_card or "You are roleplaying a character." + system += " Respond using Classic Internet RP formatting: *action* speech *narration*." + return [{"role": "system", "content": system}, {"role": "user", "content": prompt}] + + def role_expert(self, prompt: str, character_card: Optional[str] = None, template: Optional[Union[str, list, Callable]] = None, max_tokens: int = 400, temperature: float = 0.9, **gen_kwargs) -> str: + messages = self._build_messages(template, prompt, self._default_role_messages, character_card=character_card) + text, tokens, dt, deltas = self._exec_chat("RoleExpert", messages, max_tokens, temperature, **gen_kwargs) + return self._finalize("RoleExpert", prompt, text, dt, tokens, deltas, "custom" if template is not None else "default") + + def _default_affect_messages(self, text: str) -> List[Dict[str, Any]]: + system = "You are a compact classifier. Output only valid JSON." + user = f'Classify the emotional tone of this text:\n{text}\nReturn: {{"emotion": "...", "confidence": 0-1, "evidence": "..."}}' + return [{"role": "system", "content": system}, {"role": "user", "content": user}] + + def affect_expert(self, text: str, template: Optional[Union[str, list, Callable]] = None, max_tokens: int = 300, temperature: float = 0.3, **gen_kwargs) -> str: + messages = self._build_messages(template, text, self._default_affect_messages) + out, tokens, dt, deltas = self._exec_chat("AffectExpert", messages, max_tokens, temperature, **gen_kwargs) + return self._finalize("AffectExpert", text, out, dt, tokens, deltas, "custom" if template is not None else "default") + + def _default_vision_messages(self, prompt: str, image: Optional[str] = None) -> List[Dict[str, Any]]: + if not image: + return [{"role": "user", "content": prompt}] + data_uri = image if self._is_url(image) else self._image_to_data_uri(image) + content = [ + {"type": "image_url", "image_url": {"url": data_uri}}, + {"type": "text", "text": prompt}, + ] + return [{"role": "user", "content": content}] + + def _run_multimodal(self, expert_name: str, prompt: str, image: Optional[str], template: Optional[Union[str, list, Callable]], max_tokens: int, temperature: float, **gen_kwargs) -> str: + messages = self._build_messages(template, prompt, self._default_vision_messages, image=image) + text, tokens, dt, deltas = self._exec_chat(expert_name, messages, max_tokens, temperature, **gen_kwargs) + return self._finalize(expert_name, prompt, text, dt, tokens, deltas, "custom" if template is not None else "default") + + def vision_expert(self, prompt: str, image: Optional[str] = None, template: Optional[Union[str, list, Callable]] = None, max_tokens: int = 512, temperature: float = 0.4, **gen_kwargs) -> str: + return self._run_multimodal("VisionExpert", prompt, image, template, max_tokens, temperature, **gen_kwargs) + + def head_expert(self, prompt: str, image: Optional[str] = None, template: Optional[Union[str, list, Callable]] = None, max_tokens: int = 512, temperature: float = 0.4, **gen_kwargs) -> str: + return self._run_multimodal("HeadExpert", prompt, image, template, max_tokens, temperature, **gen_kwargs) + + def _default_math_messages(self, prompt: str) -> List[Dict[str, Any]]: + system = "You are a precise math and reasoning assistant." + user = f"Solve the following. Show formulas, compute carefully, and state the final answer clearly.\n\n{prompt}" + return [{"role": "system", "content": system}, {"role": "user", "content": user}] + + def math_expert(self, prompt: str, template: Optional[Union[str, list, Callable]] = None, max_tokens: int = 500, temperature: float = 0.2, **gen_kwargs) -> str: + messages = self._build_messages(template, prompt, self._default_math_messages) + text, tokens, dt, deltas = self._exec_chat("MathExpert", messages, max_tokens, temperature, repeat_penalty=1.15, **gen_kwargs) + if CHINESE_RE.search(text): + text = self._translate_chinese_spans(text) + text = collapse_repeated_lines(text, max_repeat=1) + return self._finalize("MathExpert", prompt, text, dt, tokens, deltas, "custom" if template is not None else "default") + + def _default_tool_prompt(self, task_instruction: str, tools_json: str, format_instruction: str, query: str) -> str: + return ( + "You are an AI assistant for function calling. For politically sensitive questions, " + "security and privacy issues, and other non-computer science questions, you will refuse " + "to answer\n" + "### Instruction:\n" + f"[BEGIN OF TASK INSTRUCTION]\n{task_instruction}\n[END OF TASK INSTRUCTION]\n\n" + f"[BEGIN OF AVAILABLE TOOLS]\n{tools_json}\n[END OF AVAILABLE TOOLS]\n\n" + f"[BEGIN OF FORMAT INSTRUCTION]\n{format_instruction}\n[END OF FORMAT INSTRUCTION]\n\n" + f"[BEGIN OF QUERY]\n{query}\n[END OF QUERY]\n\n" + "### Response:\n" + ) + + @staticmethod + def _safe_parse_tool_json(text: str) -> Optional[Dict[str, Any]]: + text = text.strip() + try: + return json.loads(text) + except json.JSONDecodeError: + start, end = text.find("{"), text.rfind("}") + if start != -1 and end != -1 and end > start: + try: + return json.loads(text[start:end + 1]) + except json.JSONDecodeError: + return None + return None + + def tool_expert(self, query: str, tools: Optional[List[Dict[str, Any]]] = None, task_instruction: Optional[str] = None, format_instruction: Optional[str] = None, template: Optional[Union[str, Callable]] = None, max_tokens: int = 512, temperature: float = 0.2, **gen_kwargs) -> str: + tools = tools or [] + task_instruction = task_instruction or self._XLAM_TASK_INSTRUCTION_DEFAULT + format_instruction = format_instruction or self._XLAM_FORMAT_INSTRUCTION_DEFAULT + tools_json = json.dumps(tools, indent=2) + + if template is not None: + stop = gen_kwargs.pop("stop", ["### Instruction:"]) + raw_prompt = template(query, tools, task_instruction, format_instruction) if callable(template) else str(template).format(query=query, tools=tools_json, task_instruction=task_instruction, format_instruction=format_instruction) + else: + stop = ["### Instruction:"] + raw_prompt = self._default_tool_prompt(task_instruction, tools_json, format_instruction, query) + + raw_text, tokens, dt, deltas = self._exec_completion("ToolExpert", raw_prompt, max_tokens, temperature, stop=stop, **gen_kwargs) + parsed = self._safe_parse_tool_json(raw_text) + final_text = json.dumps(parsed, indent=2) if parsed is not None else raw_text.strip() + return self._finalize("ToolExpert", query, final_text, dt, tokens, deltas, "custom" if template is not None else "default") + + def translation_expert(self, text: str) -> str: + return self.translate_zh_en(text) + + def save_checkpoint(self, path: str = DEFAULT_CHECKPOINT_PATH) -> None: + self.unload_all() + torch.save(self, path) + + @classmethod + def load_checkpoint(cls, path: str = DEFAULT_CHECKPOINT_PATH) -> "PackedLM": + return torch.load(path, map_location="cpu", weights_only=False) + + def run_self_test(self, image_test_source: Optional[str] = None) -> Dict[str, Any]: + prompts = { + "CreativeExpert": "Write a short fantasy story (150 words max) about a dragon that discovers a computer hidden beneath a mountain.", + "CodeExpert": "Write a Python implementation of quicksort. Complete runnable function, include comments, briefly explain time complexity.", + "LogicExpert": "All robots can compute. Some computers are robots. No calculators are robots. What conclusions can be logically inferred?", + "RoleExpert": "Explain how transformer attention works while staying fully in character.", + "HeadExpert": "Explain how Mixture-of-Experts (MoE) routing works. Focus on: expert selection, gating, token routing, and efficiency benefits.", + "MathExpert": "A train travels 120 miles in 2 hours and then 180 miles in 3 hours. What was its average speed for the entire trip?", + "ToolExpert": "What is the weather in St. Louis right now?", + "AffectExpert": "Your core navigation router is completely dropping telemetry packets! Fix this or we pull our implementation down tonight!", + "VisionExpert": "Describe the visual elements, layout, and any text in this image.", + "TranslationExpert": "你好,世界。这个模型应该把中文翻译成英文。", + } + + report: Dict[str, Any] = {} + for name in self.keys(): + if name not in prompts: + continue + try: + if name == "LogicExpert": + report[name] = {mode: self.logic_expert(prompts[name], mode=mode) for mode in ("deep_then_answer", "skip_reasoning", "think_only")} + elif name in ("HeadExpert", "VisionExpert"): + img = image_test_source if (image_test_source and os.path.exists(image_test_source)) else None + method = self.head_expert if name == "HeadExpert" else self.vision_expert + report[name] = method(prompts[name], image=img) + elif name == "ToolExpert": + report[name] = self.tool_expert(prompts[name], tools=[ + {"name": "get_weather", "description": "Get current weather for a city", "parameters": {"city": "string"}}, + {"name": "send_discord_message", "description": "Send a message to a Discord webhook", "parameters": {"webhook_url": "string", "content": "string"}}, + ]) + elif name == "TranslationExpert": + report[name] = self.translation_expert(prompts[name]) + else: + dispatch = { + "CreativeExpert": self.creative_expert, + "CodeExpert": self.code_expert, + "RoleExpert": self.role_expert, + "AffectExpert": self.affect_expert, + "MathExpert": self.math_expert, + } + report[name] = dispatch[name](prompts[name]) + except Exception as e: + report[name] = f"[ERROR] {type(e).__name__}: {e}" + + return {"per_expert_responses": report, "summary": self.summary()} + + +__all__ = ["PackedLM", "ExpertHandle", "HardwareProbe", "capture_telemetry", "calculate_delta"] + + +class PackedLMCheckpointRuntime: + """Load and operate a serialized PackedLM checkpoint. + + Parameters + ---------- + checkpoint_path: + Path to the saved `LM.pt` checkpoint. + packedlm_module: + Optional module name to import before loading. Use this when the + `PackedLM` class lives in a separate Python module. + Examples: "packedlm", "my_project.packedlm", or None if the class + is already imported in the current process. + map_location: + Passed to `torch.load`. Usually "cpu". + weights_only: + Must be False for a full object checkpoint saved with `torch.save(obj, ...)`. + strict_type_check: + If True, verifies that the loaded object looks like a PackedLM instance. + """ + + def __init__( + self, + checkpoint_path: Union[str, Path] = "LM.pt", + packedlm_module: Optional[str] = None, + map_location: str = "cpu", + weights_only: bool = False, + strict_type_check: bool = True, + ): + self.checkpoint_path = Path(checkpoint_path) + self.packedlm_module = packedlm_module + self.map_location = map_location + self.weights_only = weights_only + self.strict_type_check = strict_type_check + + self.model: Any = None + self.load() + + def _import_checkpoint_module(self) -> None: + if not self.packedlm_module: + return + importlib.import_module(self.packedlm_module) + + def _validate_model(self) -> None: + if self.model is None: + raise RuntimeError("PackedLM checkpoint is not loaded.") + + required_attrs = [ + "creative_expert", + "code_expert", + "logic_expert", + "role_expert", + "affect_expert", + "head_expert", + "vision_expert", + "math_expert", + "tool_expert", + "translation_expert", + "summary", + "run_self_test", + ] + missing = [name for name in required_attrs if not hasattr(self.model, name)] + if missing and self.strict_type_check: + raise TypeError( + "Loaded object does not look like a PackedLM instance. Missing: " + + ", ".join(missing) + ) + + def load(self) -> Any: + if not self.checkpoint_path.exists(): + raise FileNotFoundError(f"Checkpoint not found: {self.checkpoint_path}") + + self._import_checkpoint_module() + + # The checkpoint is a full serialized object, so weights_only must be False. + self.model = torch.load( + self.checkpoint_path, + map_location=self.map_location, + weights_only=self.weights_only, + ) + self._validate_model() + return self.model + + def reload(self) -> Any: + self.model = None + return self.load() + + def __getattr__(self, name: str) -> Any: + # Delegate unknown attributes to the loaded PackedLM object. + if name in {"model", "checkpoint_path", "packedlm_module", "map_location", "weights_only", "strict_type_check"}: + return super().__getattribute__(name) + if self.model is not None and hasattr(self.model, name): + return getattr(self.model, name) + raise AttributeError(name) + + def __getitem__(self, key: str) -> Any: + return self.model[key] + + def __contains__(self, key: str) -> bool: + return key in self.model + + @property + def last_expert(self) -> str: + return getattr(self.model, "last_expert", "") + + def experts(self) -> List[str]: + return list(self.model.keys()) + + def summary(self) -> Dict[str, Any]: + return self.model.summary() + + def creative( + self, + prompt: str, + **kwargs: Any, + ) -> str: + return self.model.creative_expert(prompt, **kwargs) + + def code( + self, + prompt: str, + **kwargs: Any, + ) -> str: + return self.model.code_expert(prompt, **kwargs) + + def logic( + self, + prompt: str, + mode: str = "deep_then_answer", + **kwargs: Any, + ) -> str: + return self.model.logic_expert(prompt, mode=mode, **kwargs) + + def role( + self, + prompt: str, + **kwargs: Any, + ) -> str: + return self.model.role_expert(prompt, **kwargs) + + def affect( + self, + text: str, + **kwargs: Any, + ) -> str: + return self.model.affect_expert(text, **kwargs) + + def head( + self, + prompt: str, + image: Optional[str] = None, + **kwargs: Any, + ) -> str: + return self.model.head_expert(prompt, image=image, **kwargs) + + def vision( + self, + prompt: str, + image: Optional[str] = None, + **kwargs: Any, + ) -> str: + return self.model.vision_expert(prompt, image=image, **kwargs) + + def math( + self, + prompt: str, + **kwargs: Any, + ) -> str: + text=self.model.math_expert(prompt, **kwargs) + text=collapse_repeated_lines(text) + return text + + def tool( + self, + query: str, + tools: Optional[List[Dict[str, Any]]] = None, + **kwargs: Any, + ) -> str: + return self.model.tool_expert(query, tools=tools, **kwargs) + + def translation(self, text: str) -> str: + return self.model.translation_expert(text) + + def reload_expert(self, expert_name: str) -> Any: + return self.model.reload_expert(expert_name) + + def unload_expert(self, expert_name: str) -> None: + return self.model.unload_expert(expert_name) + + def unload_all(self) -> None: + return self.model.unload_all() + + def save_checkpoint(self, path: Union[str, Path] = "LM.pt") -> None: + return self.model.save_checkpoint(str(path)) + + def run_self_test(self, image_test_source: Optional[str] = None) -> Dict[str, Any]: + return self.model.run_self_test(image_test_source=image_test_source) + + def __repr__(self) -> str: + model_name = type(self.model).__name__ if self.model is not None else "" + return f"PackedLMCheckpointRuntime(checkpoint_path={self.checkpoint_path!s}, model={model_name})" + +def load_packedlm( + checkpoint_path: Union[str, Path] = "LM.pt", + packedlm_module: Optional[str] = None, + map_location: str = "cpu", + weights_only: bool = False, + strict_type_check: bool = True, +) -> PackedLMCheckpointRuntime: + """Load a PackedLM checkpoint into a runtime wrapper.""" + return PackedLMCheckpointRuntime( + checkpoint_path=checkpoint_path, + packedlm_module=packedlm_module, + map_location=map_location, + weights_only=weights_only, + strict_type_check=strict_type_check, + ) + +@dataclass +class RouteStep: + expert: str + sub_prompt: str + goal: str + kwargs: Dict[str, Any] = field(default_factory=dict) + + +@dataclass +class ExecutionContext: + prompt: str + image: Optional[str] = None + tools: Optional[List[Dict[str, Any]]] = None + deep_think: bool = False + fast_think: bool = False + think_blocks: Dict[str, str] = field(default_factory=dict) + response_goal: Dict[str, Any] = field(default_factory=dict) + route: List["RouteStep"] = field(default_factory=list) + step_results: List[Dict[str, Any]] = field(default_factory=list) + base_response: str = "" + affective_state: Dict[str, Any] = field(default_factory=dict) + final_response: str = "" + final_review: Dict[str, Any] = field(default_factory=dict) + command_context: Dict[str, Any] = field(default_factory=dict) + + +class PackedLLM(nn.ModuleDict): + MODEL_EXPERTS: List[str] = [ + "head_expert", "affect_expert", "role_expert", "creative_expert", + "code_expert", "logic_expert", "math_expert", "vision_expert", + "tool_expert", "translation_expert", + ] + PIPELINE_EXPERTS: List[str] = ["action_expert", "web_expert"] + REQUIRED_EXPERTS: List[str] = MODEL_EXPERTS + PIPELINE_EXPERTS + + MAX_STEP_RETRIES: int = 3 + MAX_ACTION_ATTEMPTS: int = 3 + MAX_WEB_ROUNDS: int = 3 + + _CHECKPOINT_FORMAT_VERSION: int = 3 + _STAGE_SETTINGS: Dict[str, Dict[str, Any]] = { + "head_plan_response_goal": {"temperature": 0.2}, + "head_build_route": {"temperature": 0.5}, + "head_retry_or_reroute": {"temperature": 0.8, "top_p": 0.9}, + "head_plan_detour": {"temperature": 1.0, "top_p": 0.95}, + "head_synthesize_base": {"temperature": 1.0, "top_p": 0.95}, + "head_review_final_response": {"temperature": 0.0}, + "head_action_review": {"temperature": 1.0, "top_p": 0.95}, + "head_web_queries": {"temperature": 0.5}, + "head_web_answer_subquery": {"temperature": 0.5}, + "head_web_review": {"temperature": 1.0, "top_p": 0.95}, + "head_web_synthesis": {"temperature": 0.8, "top_p": 0.9}, + "head_validate_response": {"temperature": 0.8, "top_p": 0.9}, + "affect_evaluate_step": {"temperature": 0.2}, + "affect_build_affective_state": {"temperature": 0.5}, + "role_apply_persona": {"temperature": 1.0, "top_p": 0.95}, + "logic_action_planning": {"temperature": 0.0}, + "code_action_generation": {"temperature": 0.0}, + "logic_action_repair": {"temperature": 0.0}, + "deep_think": {"temperature": 0.0}, + } + def __init__( + self, + bot_id: Optional[str] = None, + user_id: Optional[str] = None, + model_dir: str = "models", + memory_dir: Optional[str] = None, + web: bool = False, + hardware_probe: bool = True, + expert_modules: Optional[Dict[str, nn.Module]] = None, + packedlm_checkpoint: Optional[str] = "LM.pt", + packedlm_module: Optional[str] = "PackedLM", + ): + super().__init__() + + self.bot_id = bot_id + self.user_id = user_id + self.model_dir = model_dir + self.memory_dir = memory_dir + self._hardware_probe_enabled = hardware_probe + + self.packedlm_checkpoint = self._resolve_local_path(packedlm_checkpoint) + self.packedlm_module = packedlm_module + + self._memory_bank: Any = None + self._bot_profile: Dict[str, Any] = {} + self._user_profile: Dict[str, Any] = {} + self._hardware_state: Dict[str, Any] = {} + self._web: Any = None + self._codebox: Any = None + + self._packedlm_runtime: Optional[Any] = None + self._runtime_expert_names: List[str] = [] + + self._init_packedlm_runtime() + + if self._packedlm_runtime is None: + self._build_experts(expert_modules) + + self._init_memory() + self._load_profiles() + + if hardware_probe: + self._probe_hardware() + + if web: + self._attach_web() + + # ------------------------------------------------------------------ + # Pickle support – live handles must never be serialised + # ------------------------------------------------------------------ + + def __getstate__(self): + state = self.__dict__.copy() + state["_packedlm_runtime"] = None + state["_web"] = None + state["_codebox"] = None + state["_memory_bank"] = None + return state + + def __setstate__(self, state): + self.__dict__.update(state) + self._runtime_expert_names = self.__dict__.get("_runtime_expert_names", []) + self._packedlm_runtime = None + self._web = None + self._codebox = None + self._memory_bank = None + self._init_packedlm_runtime() + + # ------------------------------------------------------------------ + # Path helpers + # ------------------------------------------------------------------ + + def _resolve_local_path(self, path: Optional[str]) -> Optional[str]: + if not path: + return None + p = Path(path) + if p.is_absolute(): + return str(p) + script_dir = Path(__file__).resolve().parent + candidate = script_dir / p + if candidate.exists(): + return str(candidate) + return str(p.resolve()) + + def _project_root(self) -> Path: + try: + return Path(__file__).resolve().parent + except Exception: + return Path.cwd() + + # ------------------------------------------------------------------ + # Initialisation helpers + # ------------------------------------------------------------------ + + def _init_packedlm_runtime(self) -> None: + if not self.packedlm_checkpoint or PackedLMCheckpointRuntime is None: + return + if not os.path.exists(self.packedlm_checkpoint): + return + + try: + self._packedlm_runtime = PackedLMCheckpointRuntime( + checkpoint_path=self.packedlm_checkpoint, + packedlm_module=self.packedlm_module, + map_location="cpu", + weights_only=False, + strict_type_check=True, + ) + raw_names = list(self._packedlm_runtime.experts()) + self._runtime_expert_names = _expert_names_canonical(raw_names) + except Exception as exc: + print(f"[PackedLLM] Warning: could not load PackedLM runtime: {exc}") + self._packedlm_runtime = None + self._runtime_expert_names = [] + + def _build_experts(self, expert_modules: Optional[Dict[str, nn.Module]]) -> None: + if expert_modules: + for key, module in expert_modules.items(): + self[key] = module + return + + class_map = { + "head_expert": ("HeadExpert", {"model_dir": self.model_dir}), + "affect_expert": ("AffectExpert", {"model_dir": self.model_dir}), + "role_expert": ("RoleExpert", {"model_dir": self.model_dir}), + "creative_expert": ("CreativeExpert", {"model_dir": self.model_dir}), + "code_expert": ("CodeExpert", {"model_dir": self.model_dir}), + "logic_expert": ("LogicExpert", {"model_dir": self.model_dir}), + "math_expert": ("MathExpert", {"model_dir": self.model_dir}), + "vision_expert": ("VisionExpert", {"model_dir": self.model_dir}), + "tool_expert": ("ToolExpert", {"model_dir": self.model_dir}), + "translation_expert": ("TranslationExpert", {"model_dir": self.model_dir}), + "action_expert": ("ActionExpert", {"model_dir": self.model_dir}), + "web_expert": ("WebExpert", {"model_dir": self.model_dir}), + } + + frame_globals: Dict[str, Any] = {} + try: + frame = inspect.stack()[2].frame + frame_globals = frame.f_globals + except Exception: + pass + + for key, (cls_name, kwargs) in class_map.items(): + cls = frame_globals.get(cls_name) or builtins.__dict__.get(cls_name) + if cls is not None: + try: + self[key] = cls(**kwargs) + except Exception as exc: + print(f"[PackedLLM] Warning: could not instantiate {cls_name}: {exc}") + + def _init_memory(self) -> None: + if MemoryBank is None: + return + try: + root = Path(self.memory_dir).expanduser().resolve() if self.memory_dir else self._project_root() + self._memory_bank = MemoryBank( + gator_location=root, + build_if_missing=False, + ) + if hasattr(self._memory_bank, "gator") and hasattr(self._memory_bank.gator, "set_lazy"): + self._memory_bank.gator.set_lazy(True) + except Exception as exc: + print(f"[PackedLLM] Warning: MemoryBank degraded mode: {exc}") + self._memory_bank = None + + def _load_profiles(self) -> None: + if self._memory_bank is None: + return + + if self.bot_id: + try: + self._bot_profile = _safe_call(self._memory_bank, "get_profile", "bot", self.bot_id, default={}) or {} + except Exception: + self._bot_profile = {} + + if self.user_id: + try: + self._user_profile = _safe_call(self._memory_bank, "get_profile", "user", self.user_id, default={}) or {} + except Exception: + self._user_profile = {} + + def _probe_hardware(self) -> None: + state: Dict[str, Any] = { + "platform": platform.system(), + "python_version": platform.python_version(), + "cpu_count": os.cpu_count(), + } + + if psutil is not None: + try: + vm = psutil.virtual_memory() + state["ram_total_gb"] = round(vm.total / 1e9, 1) + state["ram_available_gb"] = round(vm.available / 1e9, 1) + state["ram_percent_used"] = vm.percent + except Exception: + pass + + if torch.cuda.is_available(): + try: + state["gpu_name"] = torch.cuda.get_device_name(0) + props = torch.cuda.get_device_properties(0) + state["gpu_vram_total_gb"] = round(props.total_memory / 1e9, 1) + state["gpu_vram_used_gb"] = round(torch.cuda.memory_allocated(0) / 1e9, 2) + except Exception: + pass + else: + state["gpu"] = "none" + + self._hardware_state = state + + def _attach_web(self) -> None: + try: + if Web is None: + raise RuntimeError("CompileWeb.Web unavailable") + self._web = Web() + except Exception as exc: + print(f"[PackedLLM] Warning: Web module unavailable: {exc}") + self._web = None + + def _get_codebox(self) -> Any: + if self._codebox is not None: + return self._codebox + + if Box is not None: + try: + self._codebox = Box() + return self._codebox + except Exception as exc: + print(f"[PackedLLM] Warning: Box unavailable: {exc}") + + if CodeBox is not None: + try: + self._codebox = CodeBox() + return self._codebox + except Exception as exc: + print(f"[PackedLLM] Warning: CodeBox unavailable: {exc}") + + return None + + def _stage_kwargs(self, stage: str) -> Dict[str, Any]: + return dict(self._STAGE_SETTINGS.get(stage, {})) + + def _inject_think_blocks( + self, + ctx: ExecutionContext, + *, + stage: str, + target_expert: str, + task_prompt: str, + output_contract: str, + constraints: Optional[List[str]] = None, + ) -> str: + if not ctx.deep_think or target_expert == "translation_expert": + return task_prompt + + cache_key = f"{stage}::{target_expert}::{hash(task_prompt) & 0xFFFFFFFF}" + if cache_key in ctx.think_blocks: + think = ctx.think_blocks[cache_key] + else: + constraints_text = "\n".join(f"- {c}" for c in (constraints or [])) or "- none" + + think_prompt = ( + "You are LogicExpert. Produce PRIVATE planning blocks only.\n" + "Return ONLY ... blocks.\n" + "Do not answer the task. Do not produce JSON. Do not produce prose.\n" + "Make the blocks task-specific, brief, and directly useful to the target expert.\n\n" + f"Stage: {stage}\n" + f"Target expert: {target_expert}\n" + f"Task prompt:\n{task_prompt}\n\n" + f"Output contract:\n{output_contract}\n\n" + f"Constraints:\n{constraints_text}\n\n" + "Generate 2 to 4 blocks covering: objective, risks, format, and the safest path." + ) + + raw = self._call_expert("logic_expert", think_prompt, **self._stage_kwargs("deep_think")) + think = self._extract_think_blocks(raw) + ctx.think_blocks[cache_key] = think + + if think.strip(): + return ( + "\n" + f"{think.strip()}\n" + "\n\n" + f"{task_prompt}" + ) + return task_prompt + + def _extract_think_blocks(self, text: str) -> str: + if not text: + return "" + blocks = re.findall( + r".*?", + text, + flags=re.IGNORECASE | re.DOTALL, + ) + if blocks: + return "\n".join( + b.strip() + for b in blocks + if b.strip() + ) + text = text.strip() + if not text: + return "" + return f"{text}" + + def _route_allowed(self, ctx: ExecutionContext, expert: str) -> bool: + if ctx.fast_think: + return expert in {"head_expert", "role_expert", "translation_expert"} + return True + + def _fast_path_response(self, ctx: ExecutionContext) -> str: + + prompt = ( + "Answer the user's request directly and as fast as possible.\n" + "Do not call tools. Do not browse. Do not write JSON.\n" + "Do not add meta commentary.\n\n" + f"User prompt: {ctx.prompt}" + ) + return self._call_expert("head_expert", prompt, **self._stage_kwargs("head_synthesize_base")).strip() + + def _fast_apply_persona(self, ctx: ExecutionContext, base_response: str) -> str: + if not self._bot_profile: + return base_response + + character_card = self._bot_profile.get("character_card", "") + user_name = self._user_profile.get("name", "the user") + + prompt = ( + f"\nRewrite the base response in the character voice while preserving facts.\n" + f"Stay concise and accurate.\n\n\n" + f"{character_card}\n" + f"{user_name}\n" + f"{ctx.prompt}\n" + f"{base_response}" + ) + return self._call_expert("role_expert", prompt, + **self._stage_kwargs("role_apply_persona")).strip() or base_response + + # ------------------------------------------------------------------ + # Forward pass + # ------------------------------------------------------------------ + + def forward( + self, + prompt: str, + image: Optional[str] = None, + tools: Optional[List[Dict[str, Any]]] = None, + stream: bool = False, + deep_think: bool = False, + fast_think: bool = False, + ) -> Union[str, Generator[str, None, None]]: + ctx = ExecutionContext( + prompt=prompt, + image=image, + tools=tools, + deep_think=deep_think, + fast_think=fast_think, + ) + + # Fast path: minimal work, no memory, no action, no web. + if fast_think: + base = self._fast_path_response(ctx) + final = self._fast_apply_persona(ctx, base) if self._bot_profile else base + if stream: + return self._stream_response(final) + return final + + self._plan_response_goal(ctx) + self._consult_commands(ctx) + self._build_route(ctx) + self._execute_route(ctx) + self._synthesize_base(ctx) + self._build_affective_state(ctx) + self._apply_persona(ctx) + self._review_final_response(ctx) + self._finalize(ctx) + + if stream: + return self._stream_response(ctx.final_response) + return ctx.final_response + + # ------------------------------------------------------------------ + # Expert dispatch + # ------------------------------------------------------------------ + + def _call_expert(self, key: str, *args: Any, **kwargs: Any) -> str: + # Normalise key to snake_case so callers don't need to worry. + key = _normalise_expert_name(key) + + if self._packedlm_runtime is not None: + dispatch = { + "creative_expert": self._packedlm_runtime.creative, + "code_expert": self._packedlm_runtime.code, + "logic_expert": self._packedlm_runtime.logic, + "role_expert": self._packedlm_runtime.role, + "affect_expert": self._packedlm_runtime.affect, + "head_expert": self._packedlm_runtime.head, + "vision_expert": self._packedlm_runtime.vision, + "math_expert": self._packedlm_runtime.math, + "tool_expert": self._packedlm_runtime.tool, + "translation_expert": self._packedlm_runtime.translation, + "action_expert": getattr(self._packedlm_runtime, "action", None), + "web_expert": getattr(self._packedlm_runtime, "web", None), + } + fn = dispatch.get(key) + if fn is None: + return "" + try: + result = fn(*args, **kwargs) + return str(result) if result is not None else "" + except Exception as exc: + print(f"[PackedLLM] _call_expert(runtime:{key}) error: {exc}") + return "" + + expert = self._get_expert(key) + if expert is None: + return "" + try: + result = expert(*args, **kwargs) + print(result) + return str(result) if result is not None else "" + except Exception as exc: + print(f"[PackedLLM] _call_expert({key}) error: {exc}") + return "" + + # ------------------------------------------------------------------ + # Pipeline stages + # ------------------------------------------------------------------ + + def _plan_response_goal(self, ctx: ExecutionContext) -> None: + prompt = ( + "You are a response planner.\n" + "Return ONLY a JSON object with exactly these keys:\n" + "intent (string), tone (string), success (string), constraints (array), " + "needs_vision (boolean), needs_web (boolean), needs_action (boolean).\n" + "Do not add commentary, markdown, or extra keys.\n" + "Always respond in English unless the task is explicitly a translation task.\n" + "TranslationExpert is Chinese→English only; only flag translation-related routing when " + "the source text is actually Chinese.\n\n" + f"User prompt: {ctx.prompt}" + ) + prompt = self._inject_think_blocks( + ctx, + stage="head_plan_response_goal", + target_expert="head_expert", + task_prompt=prompt, + output_contract="JSON object with intent/tone/success/constraints/needs_vision/needs_web/needs_action.", + ) + raw = self._call_expert("head_expert", prompt, image=ctx.image if ctx.image else None, + **self._stage_kwargs("head_plan_response_goal")) + ctx.response_goal = _parse_json_safe(raw) or { + "intent": ctx.prompt, + "tone": "helpful", + "success": "Answer the user helpfully.", + "constraints": [], + "needs_vision": False, + "needs_web": False, + "needs_action": False, + } + + def _consult_commands(self, ctx: ExecutionContext) -> None: + if ctx.fast_think or self._memory_bank is None: + ctx.command_context = {"executed": [], "results": [], "coverage": "none"} + return + + command_context = { + "executed": [], + "results": [], + "coverage": "none", + } + + gator = getattr(self._memory_bank, "gator", None) + if gator is None: + ctx.command_context = command_context + return + + maybe_execute = getattr(gator, "maybe_execute_commands", None) + if callable(maybe_execute): + try: + result = maybe_execute(ctx.prompt, ctx.response_goal) + if isinstance(result, dict): + command_context.update(result) + except Exception as exc: + command_context["results"].append({"error": str(exc)}) + else: + try: + if hasattr(gator, "process_actions"): + routed = gator.process_actions( + ctx.prompt, + user_id=self.user_id or "", + bot_id=self.bot_id or "", + history="", + location="", + time_date="", + ) + if isinstance(routed, dict): + command_context["executed"] = routed.get("commands", []) + command_context["results"] = routed.get("retrieved_data", {}) + if routed.get("commands") or routed.get("retrieved_data"): + command_context["coverage"] = "partial" + except Exception as exc: + command_context["results"].append({"error": str(exc)}) + + if command_context["coverage"] == "none": + executed = command_context.get("executed") or [] + results = command_context.get("results") or [] + if executed or results: + command_context["coverage"] = "partial" + + ctx.command_context = command_context + + def _build_route(self, ctx: ExecutionContext) -> None: + if ctx.fast_think: + ctx.route = [RouteStep(expert="head_expert", sub_prompt=ctx.prompt, + goal="Produce the fastest useful answer possible.")] + if self._bot_profile: + ctx.route.append(RouteStep(expert="role_expert", sub_prompt=ctx.prompt, goal="Apply persona only.")) + return + + prompt = ( + "You are a response router.\n" + "Return ONLY a JSON array of step objects.\n" + "Each step object must include: expert (string), sub_prompt (string), goal (string), " + "and optional kwargs (object).\n" + "Use the fewest steps needed. Prefer web_expert for live information, action_expert for " + "executable tasks, and head_expert for planning/validation.\n" + "Always write sub_prompt and goal in English.\n" + "Do not include duplicate or redundant steps.\n\n" + f"Response goal: {json.dumps(ctx.response_goal, ensure_ascii=False, default=str)}\n" + f"Command context: {json.dumps(ctx.command_context, ensure_ascii=False, default=str)}\n" + f"Original prompt: {ctx.prompt}\n" + f"Available experts: {', '.join(self.REQUIRED_EXPERTS)}" + ) + prompt = self._inject_think_blocks( + ctx, + stage="head_build_route", + target_expert="head_expert", + task_prompt=prompt, + output_contract="JSON array of routing steps.", + ) + + raw = self._call_expert("head_expert", prompt, **self._stage_kwargs("head_build_route")) + steps_raw = _parse_json_safe(raw) + + route: List[RouteStep] = [] + if isinstance(steps_raw, list) and steps_raw: + for s in steps_raw: + if not isinstance(s, dict): + continue + expert = _normalise_expert_name(s.get("expert", "head_expert")) + if not self._route_allowed(ctx, expert): + continue + route.append( + RouteStep( + expert=expert, + sub_prompt=str(s.get("sub_prompt", ctx.prompt)), + goal=str(s.get("goal", "Complete the sub-task.")), + kwargs=s.get("kwargs", {}) if isinstance(s.get("kwargs", {}), dict) else {}, + ) + ) + + if not route: + goal = ctx.response_goal if isinstance(ctx.response_goal, dict) else {} + if goal.get("needs_web") and self._route_allowed(ctx, "web_expert"): + route.append(RouteStep(expert="web_expert", sub_prompt=ctx.prompt, + goal="Gather and synthesize fresh external information.")) + if goal.get("needs_action") and self._route_allowed(ctx, "action_expert"): + route.append(RouteStep(expert="action_expert", sub_prompt=ctx.prompt, + goal="Execute the requested action or code workflow.")) + if goal.get("needs_vision") and ctx.image and self._route_allowed(ctx, "vision_expert"): + route.append( + RouteStep(expert="vision_expert", sub_prompt=ctx.prompt, goal="Interpret the provided image.", + kwargs={"image": ctx.image})) + route.append( + RouteStep(expert="head_expert", sub_prompt=ctx.prompt, goal="Produce a complete, helpful response.")) + + # Remove redundant consecutive steps. + compressed: List[RouteStep] = [] + for step in route: + if compressed and compressed[-1].expert == step.expert and step.expert != "translation_expert": + continue + compressed.append(step) + ctx.route = compressed + + def _execute_route(self, ctx: ExecutionContext) -> None: + i = 0 + while i < len(ctx.route): + step = ctx.route[i] + + if step.expert == "action_expert": + result = self._run_action_pipeline(ctx, step) + ctx.step_results.append({ + "expert": step.expert, + "sub_prompt": step.sub_prompt, + "result": result, + "passed": bool(result.get("passed", False)), + "action": result.get("action", "action_pipeline"), + }) + i += 1 + continue + + if step.expert == "web_expert": + result = self._run_web_pipeline(ctx, step) + ctx.step_results.append({ + "expert": step.expert, + "sub_prompt": step.sub_prompt, + "result": result, + "passed": bool(result.get("passed", False)), + "action": result.get("action", "web_pipeline"), + }) + i += 1 + continue + + retries = 0 + while True: + result = self._execute_step(step, ctx) + passed = self._evaluate_step(result, step, ctx) + + if passed: + ctx.step_results.append({ + "expert": step.expert, + "sub_prompt": step.sub_prompt, + "result": result, + "passed": True, + }) + break + + retries += 1 + action = self._retry_or_reroute(step, retries, result, ctx) + + if action == "retry" and retries < self.MAX_STEP_RETRIES: + continue + + if action == "detour": + new_steps = self._plan_detour(step, result, ctx) + ctx.route = ctx.route[:i + 1] + new_steps + ctx.route[i + 1:] + ctx.step_results.append({ + "expert": step.expert, + "sub_prompt": step.sub_prompt, + "result": result, + "passed": False, + "action": "detour", + }) + break + + ctx.step_results.append({ + "expert": step.expert, + "sub_prompt": step.sub_prompt, + "result": result, + "passed": False, + "action": "skip", + }) + break + + i += 1 + + def _execute_step(self, step: RouteStep, ctx: ExecutionContext) -> str: + kwargs = dict(step.kwargs) + + if step.expert in ("head_expert", "vision_expert") and ctx.image: + kwargs.setdefault("image", ctx.image) + if step.expert == "tool_expert" and ctx.tools: + kwargs.setdefault("tools", ctx.tools) + + if step.expert == "translation_expert": + # Translation stays direct; no deep-think wrapper. + kwargs = {} + if not CHINESE_RE.search(step.sub_prompt or "") and not CHINESE_RE.search(ctx.prompt or ""): + return step.sub_prompt + + prompt_text = step.sub_prompt + if ctx.deep_think and step.expert != "translation_expert": + prompt_text = self._inject_think_blocks( + ctx, + stage=f"{step.expert}:{step.goal}", + target_expert=step.expert, + task_prompt=step.sub_prompt, + output_contract="Task-specific expert response.", + constraints=[step.goal], + ) + + return self._call_expert(step.expert, prompt_text, **kwargs) + + def _evaluate_step(self, result: str, step: RouteStep, ctx: ExecutionContext) -> bool: + meta = ( + "Evaluate whether the following result meets the stated goal. " + "Return ONLY JSON: {\"pass\": true/false, \"reason\": \"...\"}.\n\n" + f"Goal: {step.goal}\n" + f"Result: {result[:500]}" + ) + raw = self._call_expert("affect_expert", meta) + parsed = _parse_json_safe(raw) + if isinstance(parsed, dict): + return bool(parsed.get("pass", True)) + return True + + def _retry_or_reroute(self, step: RouteStep, retry_count: int, result: str, ctx: ExecutionContext) -> str: + options = ["detour", "skip"] + if retry_count < self.MAX_STEP_RETRIES: + options = ["retry"] + options + + meta = ( + "A pipeline step has failed its quality check. Decide what to do.\n" + f"Failed expert: {step.expert}\n" + f"Sub-prompt: {step.sub_prompt}\n" + f"Step goal: {step.goal}\n" + f"Result so far: {result[:300]}\n" + f"Retry count: {retry_count}\n" + f"Available options: {options}\n" + "Return ONLY JSON: {\"action\": \"