Spaces:
Paused
Paused
| #!/usr/bin/env python3 | |
| """ | |
| Terminal Agent β Hugging Face Spaces Deployment | |
| Serves web terminal + API on port 7860 | |
| """ | |
| import json | |
| import math | |
| import os | |
| import signal | |
| import subprocess | |
| import sqlite3 | |
| import threading | |
| import time | |
| import logging | |
| import sys | |
| import uuid | |
| import re | |
| import hashlib | |
| from datetime import datetime, timezone | |
| from pathlib import Path | |
| from typing import Dict, Optional | |
| from flask import Flask, jsonify, request, Response, render_template | |
| import schedule | |
| import requests | |
| # ββ Config ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| PORT = int(os.environ.get("PORT") or (Path("/app/port").read_text().strip() if Path("/app/port").exists() else 7860)) | |
| LOG_DIR = Path("logs") | |
| LOG_DIR.mkdir(exist_ok=True) | |
| NOTEBOOK_DIR = Path("notebooks") | |
| NOTEBOOK_DIR.mkdir(exist_ok=True) | |
| APPS_DIR = Path("generated_apps") | |
| APPS_DIR.mkdir(exist_ok=True) | |
| CONFIG_PATH = Path("config.json") | |
| STATE_PATH = Path("agent_state.json") | |
| MEMORY_PATH = Path("memory_store.json") | |
| SETTINGS_PATH = Path("settings.json") | |
| APPS_PATH = Path("apps_registry.json") | |
| RECEIPTS_PATH = Path("receipts_store.json") | |
| TERMINAL_AGENT_TOKEN = os.environ.get("TERMINAL_AGENT_TOKEN", "").strip() | |
| MAX_COMMAND_TIMEOUT = int(os.environ.get("MAX_COMMAND_TIMEOUT", "600")) | |
| DEFAULT_CWD = Path(os.environ.get("TERMINAL_AGENT_CWD", "/app" if Path("/app").exists() else ".")) | |
| # ββ Logging βββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| log_file = LOG_DIR / f"agent_{datetime.now(timezone.utc).strftime('%Y%m%d')}.log" | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format="%(asctime)s - %(levelname)s - %(message)s", | |
| handlers=[logging.FileHandler(log_file), logging.StreamHandler(sys.stdout)], | |
| ) | |
| logger = logging.getLogger("terminal-agent") | |
| # ββ State βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| state = { | |
| "start_time": datetime.now(timezone.utc).isoformat(), | |
| "last_check": None, | |
| "executed_tasks": [], | |
| } | |
| tasks: Dict[str, dict] = {} | |
| processes: Dict[str, dict] = {} | |
| apps: Dict[str, dict] = {} | |
| receipts: Dict[str, dict] = {} | |
| memories: Dict[str, dict] = {} | |
| memory_lock = threading.RLock() | |
| app_lock = threading.RLock() | |
| receipt_lock = threading.RLock() | |
| settings_lock = threading.RLock() | |
| settings: Dict[str, dict] = {} | |
| kernel_lock = threading.RLock() | |
| kernel_manager = None | |
| kernel_client = None | |
| # ββ Token Economy (SQLite-backed, integer amounts) ββββββββββββββ | |
| DB_PATH = Path("token_economy.db") | |
| token_lock = threading.RLock() | |
| wallet_lock = threading.RLock() | |
| # Integer token amounts β no floats for money (C53) | |
| TOKEN_REWARDS = { | |
| "kernel_execute": 100, | |
| "shell_execute": 50, | |
| "notebook_run": 200, | |
| "agent_build": 500, | |
| "app_start": 100, | |
| "llm_call": 20, | |
| "deploy": 300, | |
| } | |
| # ββ Token costs: DB-first, env override, no hardcoded runtime values ββ | |
| _TOKEN_COST_DEFAULTS = { | |
| "token_launch": 5000, | |
| "claim_evaluate": 500, | |
| "claim_contradiction_scan": 200, | |
| "claim_greeks": 100, | |
| "pixelator_ingest": 300, | |
| "pixelator_glyphs": 50, | |
| "crawler_ingest": 250, | |
| "crawler_enqueue": 25, | |
| } | |
| def _get_token_cost(operation: str) -> int: | |
| """Read cost from DB first, then env, then defaults.""" | |
| # Env override takes highest precedence for admin tuning | |
| env_val = os.environ.get(f"COST_{operation.upper()}") | |
| if env_val is not None: | |
| try: | |
| return int(env_val) | |
| except ValueError: | |
| pass | |
| with _db() as conn: | |
| row = conn.execute("SELECT cost FROM token_costs WHERE operation = ?", (operation,)).fetchone() | |
| if row: | |
| return row["cost"] | |
| return _TOKEN_COST_DEFAULTS.get(operation, 0) | |
| # Solana configuration (C12: no hardcoded secrets) | |
| SOLANA_RPC_URL = os.environ.get("SOLANA_RPC_URL", "https://api.devnet.solana.com") | |
| SOLANA_MAINNET_ENABLED = os.environ.get("SOLANA_MAINNET_ENABLED", "").lower() in ("true", "1", "yes") | |
| SOLANA_SERVICE_KEY_B58 = os.environ.get("SOLANA_SERVICE_KEY_B58", "") | |
| if SOLANA_MAINNET_ENABLED: | |
| SOLANA_RPC_URL = os.environ.get("SOLANA_RPC_URL", "https://api.mainnet-beta.solana.com") | |
| def _db() -> sqlite3.Connection: | |
| conn = sqlite3.connect(str(DB_PATH), check_same_thread=False, timeout=10.0) | |
| conn.row_factory = sqlite3.Row | |
| conn.execute("PRAGMA journal_mode=WAL") | |
| conn.execute("PRAGMA synchronous=NORMAL") | |
| return conn | |
| def _init_token_db(): | |
| with _db() as conn: | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS wallets ( | |
| address TEXT PRIMARY KEY, | |
| provider TEXT NOT NULL CHECK(provider IN ('metamask','phantom')), | |
| signature TEXT NOT NULL, | |
| nonce TEXT NOT NULL, | |
| connected_at TEXT NOT NULL, | |
| last_seen TEXT NOT NULL | |
| ) | |
| """) | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS balances ( | |
| address TEXT PRIMARY KEY, | |
| balance INTEGER NOT NULL DEFAULT 0 CHECK(balance >= 0) | |
| ) | |
| """) | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS transactions ( | |
| tx_id TEXT PRIMARY KEY, | |
| address TEXT NOT NULL, | |
| amount INTEGER NOT NULL, | |
| type TEXT NOT NULL CHECK(type IN ('credit','debit')), | |
| reason TEXT NOT NULL, | |
| created_at TEXT NOT NULL, | |
| metadata TEXT | |
| ) | |
| """) | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_tx_address ON transactions(address)") | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_tx_created ON transactions(created_at)") | |
| # ββ Idempotency + Underwriting tables βββββββββββββββββββββ | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS stripe_sessions ( | |
| session_id TEXT PRIMARY KEY, | |
| event_type TEXT NOT NULL, | |
| status TEXT NOT NULL, | |
| amount_cents INTEGER NOT NULL CHECK(amount_cents >= 0), | |
| currency TEXT NOT NULL DEFAULT 'usd', | |
| wallet TEXT NOT NULL, | |
| pack TEXT NOT NULL, | |
| tokens INTEGER NOT NULL CHECK(tokens >= 0), | |
| processed_at TEXT NOT NULL, | |
| tx_id TEXT UNIQUE | |
| ) | |
| """) | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS revenue ( | |
| revenue_id TEXT PRIMARY KEY, | |
| source TEXT NOT NULL CHECK(source IN ('stripe_checkout','stripe_webhook','token_pack','other')), | |
| session_id TEXT, | |
| amount_cents INTEGER NOT NULL CHECK(amount_cents >= 0), | |
| currency TEXT NOT NULL DEFAULT 'usd', | |
| period TEXT NOT NULL, | |
| wallet TEXT, | |
| created_at TEXT NOT NULL, | |
| metadata TEXT | |
| ) | |
| """) | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS deferred_revenue ( | |
| address TEXT PRIMARY KEY, | |
| tokens_purchased INTEGER NOT NULL DEFAULT 0 CHECK(tokens_purchased >= 0), | |
| tokens_spent INTEGER NOT NULL DEFAULT 0 CHECK(tokens_spent >= 0), | |
| deferred_cents INTEGER NOT NULL DEFAULT 0 CHECK(deferred_cents >= 0), | |
| last_updated TEXT NOT NULL | |
| ) | |
| """) | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS launched_tokens ( | |
| launch_id TEXT PRIMARY KEY, | |
| mint_address TEXT NOT NULL UNIQUE, | |
| owner_address TEXT NOT NULL, | |
| name TEXT NOT NULL, | |
| symbol TEXT NOT NULL, | |
| decimals INTEGER NOT NULL DEFAULT 9, | |
| supply INTEGER NOT NULL, | |
| tx_signature TEXT, | |
| network TEXT NOT NULL DEFAULT 'devnet', | |
| created_at TEXT NOT NULL, | |
| metadata_uri TEXT | |
| ) | |
| """) | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_launched_owner ON launched_tokens(owner_address)") | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_rev_period ON revenue(period)") | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_rev_source ON revenue(source)") | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_stripe_wallet ON stripe_sessions(wallet)") | |
| # ββ CLAIMOS tables ββββββββββββββββββββββββββββββββββββββββββ | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS claims ( | |
| claim_id TEXT PRIMARY KEY, | |
| title TEXT NOT NULL, | |
| description TEXT, | |
| status TEXT NOT NULL DEFAULT 'unreviewed' CHECK(status IN ('unreviewed','evidence_received','counsel_reviewed','procedural_survival','settlement_signals','finance_ready','closed')), | |
| evidence_count INTEGER NOT NULL DEFAULT 0, | |
| p_recovery REAL DEFAULT 0.0, | |
| evidence_strength REAL DEFAULT 0.0, | |
| counsel_signal REAL DEFAULT 0.0, | |
| procedural_survival REAL DEFAULT 0.0, | |
| settlement_signal REAL DEFAULT 0.0, | |
| contradiction_density REAL DEFAULT 0.0, | |
| uncertainty REAL DEFAULT 0.0, | |
| liquidity_score REAL DEFAULT 0.0, | |
| delta_claim REAL DEFAULT 0.0, | |
| theta_claim REAL DEFAULT 0.0, | |
| gamma_claim REAL DEFAULT 0.0, | |
| vega_claim REAL DEFAULT 0.0, | |
| kappa_claim REAL DEFAULT 0.0, | |
| created_at TEXT NOT NULL, | |
| updated_at TEXT NOT NULL, | |
| wallet TEXT, | |
| metadata TEXT | |
| ) | |
| """) | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS evidence ( | |
| evidence_id TEXT PRIMARY KEY, | |
| claim_id TEXT NOT NULL, | |
| source_type TEXT NOT NULL CHECK(source_type IN ('audio','document','transcript','witness','hospital','police','screenshot','email','timeline','other')), | |
| source_ref TEXT NOT NULL, | |
| content_hash TEXT NOT NULL, | |
| content TEXT, | |
| evidence_strength REAL DEFAULT 0.5, | |
| created_at TEXT NOT NULL, | |
| metadata TEXT, | |
| FOREIGN KEY (claim_id) REFERENCES claims(claim_id) | |
| ) | |
| """) | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS contradictions ( | |
| contradiction_id TEXT PRIMARY KEY, | |
| claim_id TEXT NOT NULL, | |
| evidence_a_id TEXT NOT NULL, | |
| evidence_b_id TEXT NOT NULL, | |
| contradiction_type TEXT NOT NULL CHECK(contradiction_type IN ('temporal','causal','factual','source','semantic')), | |
| severity REAL NOT NULL DEFAULT 0.5 CHECK(severity >= 0 AND severity <= 1), | |
| description TEXT, | |
| resolved INTEGER NOT NULL DEFAULT 0, | |
| created_at TEXT NOT NULL, | |
| FOREIGN KEY (claim_id) REFERENCES claims(claim_id), | |
| FOREIGN KEY (evidence_a_id) REFERENCES evidence(evidence_id), | |
| FOREIGN KEY (evidence_b_id) REFERENCES evidence(evidence_id) | |
| ) | |
| """) | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_claims_wallet ON claims(wallet)") | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_claims_status ON claims(status)") | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_evidence_claim ON evidence(claim_id)") | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_contradictions_claim ON contradictions(claim_id)") | |
| # ββ Pixelator / GlyphIndex tables βββββββββββββββββββββββββββ | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS pages ( | |
| page_id TEXT PRIMARY KEY, | |
| website_id TEXT NOT NULL, | |
| url TEXT NOT NULL, | |
| title TEXT, | |
| page_activation_value REAL NOT NULL DEFAULT 0.0, | |
| semantic_density REAL NOT NULL DEFAULT 0.0, | |
| entity_count INTEGER NOT NULL DEFAULT 0, | |
| action_count INTEGER NOT NULL DEFAULT 0, | |
| commercial_score REAL NOT NULL DEFAULT 0.0, | |
| legal_score REAL NOT NULL DEFAULT 0.0, | |
| version_id INTEGER NOT NULL DEFAULT 1, | |
| created_at TEXT NOT NULL, | |
| metadata TEXT | |
| ) | |
| """) | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS glyph_units ( | |
| glyph_id TEXT PRIMARY KEY, | |
| page_id TEXT NOT NULL, | |
| website_id TEXT NOT NULL, | |
| version_id INTEGER NOT NULL DEFAULT 1, | |
| dom_path TEXT NOT NULL, | |
| paragraph_pos INTEGER NOT NULL DEFAULT 0, | |
| sentence_pos INTEGER NOT NULL DEFAULT 0, | |
| token_pos INTEGER NOT NULL DEFAULT 0, | |
| char_index INTEGER NOT NULL DEFAULT 0, | |
| char_value TEXT NOT NULL, | |
| char_case TEXT NOT NULL DEFAULT 'lower', | |
| semantic_role TEXT NOT NULL DEFAULT 'body', | |
| activation_role TEXT NOT NULL DEFAULT 'neutral', | |
| proof_hash TEXT, | |
| semantic_density REAL NOT NULL DEFAULT 0.0, | |
| glyph_value REAL NOT NULL DEFAULT 0.0, | |
| entity_proximity REAL NOT NULL DEFAULT 0.0, | |
| action_proximity REAL NOT NULL DEFAULT 0.0, | |
| commercial_proximity REAL NOT NULL DEFAULT 0.0, | |
| legal_proximity REAL NOT NULL DEFAULT 0.0, | |
| timestamp TEXT NOT NULL, | |
| FOREIGN KEY (page_id) REFERENCES pages(page_id) | |
| ) | |
| """) | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_glyph_page ON glyph_units(page_id)") | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_glyph_website ON glyph_units(website_id)") | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_glyph_value ON glyph_units(glyph_value)") | |
| # ββ GA-RL Crawler tables βββββββββββββββββββββββββββββββββββββ | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS crawl_targets ( | |
| target_id TEXT PRIMARY KEY, | |
| website_id TEXT NOT NULL UNIQUE, | |
| root_url TEXT NOT NULL, | |
| name TEXT, | |
| priority REAL NOT NULL DEFAULT 1.0, | |
| fitness_score REAL NOT NULL DEFAULT 0.0, | |
| avg_glyph_value REAL NOT NULL DEFAULT 0.0, | |
| crawl_count INTEGER NOT NULL DEFAULT 0, | |
| success_count INTEGER NOT NULL DEFAULT 0, | |
| last_crawled TEXT, | |
| crawl_depth INTEGER NOT NULL DEFAULT 2, | |
| selector_rules TEXT, | |
| is_active INTEGER NOT NULL DEFAULT 1, | |
| created_at TEXT NOT NULL, | |
| metadata TEXT | |
| ) | |
| """) | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS crawl_queue ( | |
| queue_id TEXT PRIMARY KEY, | |
| target_id TEXT NOT NULL, | |
| url TEXT NOT NULL, | |
| status TEXT NOT NULL DEFAULT 'pending', | |
| priority_score REAL NOT NULL DEFAULT 0.0, | |
| q_value REAL NOT NULL DEFAULT 0.0, | |
| depth INTEGER NOT NULL DEFAULT 0, | |
| added_at TEXT NOT NULL, | |
| started_at TEXT, | |
| completed_at TEXT, | |
| error_msg TEXT, | |
| page_id TEXT, | |
| reward REAL DEFAULT 0.0, | |
| FOREIGN KEY (target_id) REFERENCES crawl_targets(target_id) | |
| ) | |
| """) | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS crawl_results ( | |
| result_id TEXT PRIMARY KEY, | |
| queue_id TEXT NOT NULL, | |
| target_id TEXT NOT NULL, | |
| page_id TEXT NOT NULL, | |
| url TEXT NOT NULL, | |
| status TEXT NOT NULL, | |
| glyph_count INTEGER NOT NULL DEFAULT 0, | |
| page_activation REAL NOT NULL DEFAULT 0.0, | |
| avg_glyph_value REAL NOT NULL DEFAULT 0.0, | |
| reward REAL NOT NULL DEFAULT 0.0, | |
| crawl_time_ms INTEGER, | |
| crawled_at TEXT NOT NULL, | |
| FOREIGN KEY (target_id) REFERENCES crawl_targets(target_id) | |
| ) | |
| """) | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS crawl_policy ( | |
| policy_id TEXT PRIMARY KEY, | |
| website_id TEXT NOT NULL, | |
| q_value REAL NOT NULL DEFAULT 0.0, | |
| visit_count INTEGER NOT NULL DEFAULT 0, | |
| epsilon REAL NOT NULL DEFAULT 0.3, | |
| alpha REAL NOT NULL DEFAULT 0.1, | |
| gamma REAL NOT NULL DEFAULT 0.9, | |
| generation INTEGER NOT NULL DEFAULT 0, | |
| updated_at TEXT NOT NULL | |
| ) | |
| """) | |
| conn.execute("CREATE UNIQUE INDEX IF NOT EXISTS idx_policy_website ON crawl_policy(website_id)") | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_queue_status ON crawl_queue(status)") | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_queue_target ON crawl_queue(target_id)") | |
| conn.execute("CREATE INDEX IF NOT EXISTS idx_results_target ON crawl_results(target_id)") | |
| # ββ Learned weights / costs (no hardcoded values) ββββββββββββ | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS dom_weights ( | |
| tag TEXT PRIMARY KEY, | |
| weight REAL NOT NULL DEFAULT 1.0, | |
| sample_count INTEGER NOT NULL DEFAULT 0, | |
| avg_page_activation REAL NOT NULL DEFAULT 0.0, | |
| updated_at TEXT NOT NULL | |
| ) | |
| """) | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS semantic_lexicon ( | |
| term TEXT NOT NULL, | |
| category TEXT NOT NULL, | |
| frequency INTEGER NOT NULL DEFAULT 1, | |
| confidence REAL NOT NULL DEFAULT 0.5, | |
| source_count INTEGER NOT NULL DEFAULT 0, | |
| updated_at TEXT NOT NULL, | |
| PRIMARY KEY (term, category) | |
| ) | |
| """) | |
| conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS token_costs ( | |
| operation TEXT PRIMARY KEY, | |
| cost INTEGER NOT NULL DEFAULT 0, | |
| source TEXT NOT NULL DEFAULT 'db', | |
| updated_at TEXT NOT NULL | |
| ) | |
| """) | |
| conn.commit() | |
| # Ensure DB schema exists at import time (for WSGI / module imports) | |
| _init_token_db() | |
| def _seed_learned_tables() -> None: | |
| """Seed DB tables with initial values from defaults. Run once at startup.""" | |
| now = datetime.now(timezone.utc).isoformat() | |
| with _db() as conn: | |
| # Seed token_costs from defaults | |
| for op, cost in _TOKEN_COST_DEFAULTS.items(): | |
| conn.execute( | |
| "INSERT OR IGNORE INTO token_costs (operation, cost, source, updated_at) VALUES (?, ?, 'seed', ?)", | |
| (op, cost, now), | |
| ) | |
| # Seed DOM weights from historical empirical data | |
| dom_seed = { | |
| "h1": 3.0, "h2": 2.5, "h3": 2.0, "h4": 1.5, "h5": 1.3, "h6": 1.2, | |
| "title": 3.5, "strong": 1.8, "b": 1.8, "em": 1.5, "a": 1.4, | |
| "p": 1.0, "span": 0.8, "li": 1.1, "td": 0.9, "div": 0.7, | |
| } | |
| for tag, weight in dom_seed.items(): | |
| conn.execute( | |
| "INSERT OR IGNORE INTO dom_weights (tag, weight, sample_count, avg_page_activation, updated_at) VALUES (?, ?, 0, 0.0, ?)", | |
| (tag, weight, now), | |
| ) | |
| # Seed semantic lexicon from initial corpus | |
| lexicon_seed = [ | |
| # entity | |
| ("acquires", "entity"), ("acquired", "entity"), ("acquisition", "entity"), | |
| ("merger", "entity"), ("ipo", "entity"), ("funding", "entity"), | |
| ("launches", "entity"), ("announces", "entity"), ("partnership", "entity"), | |
| ("contract", "entity"), ("deal", "entity"), ("apple", "entity"), | |
| ("google", "entity"), ("microsoft", "entity"), ("amazon", "entity"), | |
| ("tesla", "entity"), ("nvidia", "entity"), ("startup", "entity"), | |
| ("unicorn", "entity"), ("billion", "entity"), ("million", "entity"), | |
| ("valuation", "entity"), | |
| # action | |
| ("acquires", "action"), ("buys", "action"), ("sells", "action"), | |
| ("merges", "action"), ("launches", "action"), ("announces", "action"), | |
| ("raises", "action"), ("funds", "action"), ("invests", "action"), | |
| ("partners", "action"), ("signs", "action"), ("wins", "action"), | |
| ("loses", "action"), ("grows", "action"), ("expands", "action"), | |
| ("purchased", "action"), ("sold", "action"), ("closed", "action"), | |
| # commercial | |
| ("revenue", "commercial"), ("profit", "commercial"), ("sales", "commercial"), | |
| ("market", "commercial"), ("share", "commercial"), ("price", "commercial"), | |
| ("stock", "commercial"), ("trading", "commercial"), ("investor", "commercial"), | |
| ("shareholder", "commercial"), ("dividend", "commercial"), ("earnings", "commercial"), | |
| ("quarter", "commercial"), ("fiscal", "commercial"), ("growth", "commercial"), | |
| ("expansion", "commercial"), | |
| # legal | |
| ("lawsuit", "legal"), ("patent", "legal"), ("copyright", "legal"), | |
| ("trademark", "legal"), ("settlement", "legal"), ("violation", "legal"), | |
| ("compliance", "legal"), ("regulation", "legal"), ("fda", "legal"), | |
| ("sec", "legal"), ("antitrust", "legal"), ("litigation", "legal"), | |
| ("court", "legal"), ("verdict", "legal"), ("fine", "legal"), | |
| ("sanction", "legal"), | |
| ] | |
| for term, category in lexicon_seed: | |
| conn.execute( | |
| """INSERT OR IGNORE INTO semantic_lexicon (term, category, frequency, confidence, source_count, updated_at) | |
| VALUES (?, ?, 1, 0.6, 0, ?)""", | |
| (term, category, now), | |
| ) | |
| conn.commit() | |
| _seed_learned_tables() | |
| def _normalize_wallet(address: str) -> str: | |
| """Lowercase EVM addresses; preserve Solana base58 case.""" | |
| a = address.strip() | |
| return a.lower() if a.startswith("0x") else a | |
| def _clamp_str(value, max_len: int = 4000) -> str: | |
| s = str(value) if value else "" | |
| return s[:max_len] | |
| def _connected_wallet(address: str) -> Optional[dict]: | |
| addr = _normalize_wallet(address) | |
| with wallet_lock: | |
| with _db() as conn: | |
| row = conn.execute("SELECT * FROM wallets WHERE address = ?", (addr,)).fetchone() | |
| if row: | |
| return dict(row) | |
| return None | |
| def _new_tx_id() -> str: | |
| return f"tx_{uuid.uuid4().hex}_{int(time.time() * 1000)}" | |
| def load_tokens(): | |
| pass # SQLite is self-bootstrapping | |
| def load_wallets(): | |
| pass # SQLite is self-bootstrapping | |
| def get_balance(address: str) -> int: | |
| addr = _normalize_wallet(address) | |
| with token_lock: | |
| with _db() as conn: | |
| row = conn.execute("SELECT balance FROM balances WHERE address = ?", (addr,)).fetchone() | |
| return row["balance"] if row else 0 | |
| def credit_tokens(address: str, amount: int, reason: str, metadata: Optional[dict] = None, idempotency_key: Optional[str] = None, revenue_cents: int = 0) -> dict: | |
| if amount <= 0: | |
| raise ValueError("Credit amount must be positive integer") | |
| addr = _normalize_wallet(address) | |
| tx_id = idempotency_key or _new_tx_id() | |
| now = datetime.now(timezone.utc).isoformat() | |
| period = now[:7] # YYYY-MM | |
| with token_lock: | |
| with _db() as conn: | |
| # Idempotency: if tx_id already exists, return existing record | |
| existing = conn.execute("SELECT tx_id, amount, reason FROM transactions WHERE tx_id = ?", (tx_id,)).fetchone() | |
| if existing: | |
| bal = get_balance(addr) | |
| return {"wallet": addr, "amount": existing["amount"], "reason": existing["reason"], "balance": bal, "tx_id": tx_id, "idempotent": True} | |
| conn.execute( | |
| "INSERT OR REPLACE INTO balances (address, balance) VALUES (?, COALESCE((SELECT balance FROM balances WHERE address = ?), 0) + ?)", | |
| (addr, addr, amount), | |
| ) | |
| conn.execute( | |
| "INSERT INTO transactions (tx_id, address, amount, type, reason, created_at, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)", | |
| (tx_id, addr, amount, "credit", reason, now, json.dumps(metadata) if metadata else None), | |
| ) | |
| # Revenue ledger for underwriting proof | |
| if revenue_cents > 0: | |
| rev_id = f"rev_{uuid.uuid4().hex}" | |
| conn.execute( | |
| "INSERT INTO revenue (revenue_id, source, session_id, amount_cents, currency, period, wallet, created_at, metadata) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", | |
| (rev_id, "token_pack", metadata.get("session_id") if metadata else None, revenue_cents, "usd", period, addr, now, json.dumps(metadata) if metadata else None), | |
| ) | |
| # Deferred revenue: purchased tokens increase liability (bonuses excluded) | |
| if reason.startswith("stripe_purchase"): | |
| cents_per_token = revenue_cents // amount if amount > 0 and revenue_cents > 0 else 0 | |
| conn.execute( | |
| """INSERT INTO deferred_revenue (address, tokens_purchased, tokens_spent, deferred_cents, last_updated) | |
| VALUES (?, ?, 0, ?, ?) | |
| ON CONFLICT(address) DO UPDATE SET | |
| tokens_purchased = tokens_purchased + excluded.tokens_purchased, | |
| deferred_cents = deferred_cents + excluded.deferred_cents, | |
| last_updated = excluded.last_updated""", | |
| (addr, amount, cents_per_token * amount, now), | |
| ) | |
| conn.commit() | |
| bal = get_balance(addr) | |
| add_memory( | |
| title=f"Token credit: +{amount} to {addr[:16]}...", | |
| content=f"Wallet {addr} credited {amount} tokens. Reason: {reason}. New balance: {bal}", | |
| source="token-economy", | |
| tags=["tokens", "credit", reason], | |
| metadata={"wallet": addr, "amount": amount, "reason": reason, "balance": bal, "tx_id": tx_id}, | |
| importance=0.7, | |
| ) | |
| create_receipt( | |
| kind="token-credit", | |
| title=f"Token credit: +{amount}", | |
| status="completed", | |
| command=f"credit:{amount}:{reason}", | |
| metadata={"wallet": addr, "amount": amount, "reason": reason, "balance": bal, "tx_id": tx_id}, | |
| ) | |
| return {"wallet": addr, "amount": amount, "reason": reason, "balance": bal, "tx_id": tx_id} | |
| def debit_tokens(address: str, amount: int, reason: str, metadata: Optional[dict] = None, idempotency_key: Optional[str] = None) -> dict: | |
| if amount <= 0: | |
| raise ValueError("Debit amount must be positive integer") | |
| addr = _normalize_wallet(address) | |
| tx_id = idempotency_key or _new_tx_id() | |
| now = datetime.now(timezone.utc).isoformat() | |
| with token_lock: | |
| with _db() as conn: | |
| # Idempotency | |
| existing = conn.execute("SELECT tx_id, amount, reason FROM transactions WHERE tx_id = ?", (tx_id,)).fetchone() | |
| if existing: | |
| bal = get_balance(addr) | |
| return {"wallet": addr, "amount": existing["amount"], "reason": existing["reason"], "balance": bal, "tx_id": tx_id, "idempotent": True} | |
| row = conn.execute("SELECT balance FROM balances WHERE address = ?", (addr,)).fetchone() | |
| current = row["balance"] if row else 0 | |
| if current < amount: | |
| raise ValueError(f"Insufficient tokens: {current} < {amount}") | |
| conn.execute( | |
| "UPDATE balances SET balance = balance - ? WHERE address = ?", | |
| (amount, addr), | |
| ) | |
| conn.execute( | |
| "INSERT INTO transactions (tx_id, address, amount, type, reason, created_at, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)", | |
| (tx_id, addr, amount, "debit", reason, now, json.dumps(metadata) if metadata else None), | |
| ) | |
| # Reduce deferred revenue liability when tokens are consumed | |
| conn.execute( | |
| """UPDATE deferred_revenue SET | |
| tokens_spent = tokens_spent + ?, | |
| deferred_cents = MAX(0, deferred_cents - (SELECT deferred_cents FROM deferred_revenue WHERE address = ?) / NULLIF(tokens_purchased, 0) * ?), | |
| last_updated = ? | |
| WHERE address = ? AND tokens_purchased > 0""", | |
| (amount, addr, amount, now, addr), | |
| ) | |
| conn.commit() | |
| bal = get_balance(addr) | |
| add_memory( | |
| title=f"Token debit: -{amount} from {addr[:16]}...", | |
| content=f"Wallet {addr} debited {amount} tokens. Reason: {reason}. New balance: {bal}", | |
| source="token-economy", | |
| tags=["tokens", "debit", reason], | |
| metadata={"wallet": addr, "amount": amount, "reason": reason, "balance": bal, "tx_id": tx_id}, | |
| importance=0.7, | |
| ) | |
| create_receipt( | |
| kind="token-debit", | |
| title=f"Token debit: -{amount}", | |
| status="completed", | |
| command=f"debit:{amount}:{reason}", | |
| metadata={"wallet": addr, "amount": amount, "reason": reason, "balance": bal, "tx_id": tx_id}, | |
| ) | |
| return {"wallet": addr, "amount": amount, "reason": reason, "balance": bal, "tx_id": tx_id} | |
| def leaderboard(limit: int = 20) -> list: | |
| with token_lock: | |
| with _db() as conn: | |
| rows = conn.execute( | |
| "SELECT address, balance FROM balances ORDER BY balance DESC LIMIT ?", | |
| (limit,), | |
| ).fetchall() | |
| return [{"rank": i + 1, "wallet": row["address"], "balance": row["balance"]} for i, row in enumerate(rows)] | |
| def tx_history(address: str, limit: int = 50) -> list: | |
| addr = _normalize_wallet(address) | |
| with token_lock: | |
| with _db() as conn: | |
| rows = conn.execute( | |
| "SELECT tx_id, amount, type, reason, created_at FROM transactions WHERE address = ? ORDER BY created_at DESC LIMIT ?", | |
| (addr, limit), | |
| ).fetchall() | |
| return [{"tx_id": r["tx_id"], "amount": r["amount"], "type": r["type"], "reason": r["reason"], "created_at": r["created_at"]} for r in rows] | |
| # ββ CLAIMOS Core ββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class ClaimProbabilityEngine: | |
| """Computes P(recovery_t) from evidence strength, counsel work, procedural survival, | |
| settlement signals, contradiction density, and uncertainty/risk. | |
| P(recovery_t) = Ο(E_t + L_t + P_t + S_t - C_t - R_t) | |
| """ | |
| EPS = 0.01 | |
| TIME_DECAY_DAILY = 0.002 | |
| def _sigmoid(x: float) -> float: | |
| try: | |
| return 1.0 / (1.0 + math.exp(-x)) | |
| except OverflowError: | |
| return 1.0 if x > 0 else 0.0 | |
| def evaluate(cls, claim_id: str, inputs: Optional[dict] = None) -> dict: | |
| """Evaluate or re-evaluate a claim's probability state.""" | |
| now = datetime.now(timezone.utc).isoformat() | |
| with _db() as conn: | |
| claim = conn.execute("SELECT * FROM claims WHERE claim_id = ?", (claim_id,)).fetchone() | |
| if not claim: | |
| raise ValueError(f"Claim not found: {claim_id}") | |
| # Pull all evidence for this claim | |
| ev_rows = conn.execute("SELECT * FROM evidence WHERE claim_id = ?", (claim_id,)).fetchall() | |
| # Pull all contradictions | |
| cx_rows = conn.execute("SELECT * FROM contradictions WHERE claim_id = ? AND resolved = 0", (claim_id,)).fetchall() | |
| # Compute components | |
| E = 0.0 # evidence strength | |
| if ev_rows: | |
| strengths = [r["evidence_strength"] or 0.5 for r in ev_rows] | |
| E = sum(strengths) / len(strengths) * math.log1p(len(strengths)) | |
| # Contradiction density | |
| C = 0.0 | |
| if cx_rows: | |
| severities = [r["severity"] or 0.5 for r in cx_rows] | |
| C = sum(severities) / len(severities) * math.log1p(len(severities)) | |
| # Override with explicit inputs if provided | |
| if inputs: | |
| E = inputs.get("evidence_strength", E) | |
| L = inputs.get("counsel_signal", claim["counsel_signal"] or 0.0) | |
| P = inputs.get("procedural_survival", claim["procedural_survival"] or 0.0) | |
| S = inputs.get("settlement_signal", claim["settlement_signal"] or 0.0) | |
| R = inputs.get("uncertainty", claim["uncertainty"] or 0.0) | |
| else: | |
| L = claim["counsel_signal"] or 0.0 | |
| P = claim["procedural_survival"] or 0.0 | |
| S = claim["settlement_signal"] or 0.0 | |
| R = claim["uncertainty"] or 0.0 | |
| # Probability compression: Ο(E + L + P + S - C - R) | |
| z = E + L + P + S - C - R | |
| p_recovery = cls._sigmoid(z) | |
| # Update claim record | |
| with _db() as conn: | |
| conn.execute( | |
| """UPDATE claims SET | |
| evidence_strength = ?, counsel_signal = ?, procedural_survival = ?, | |
| settlement_signal = ?, contradiction_density = ?, uncertainty = ?, | |
| p_recovery = ?, evidence_count = ?, updated_at = ? | |
| WHERE claim_id = ?""", | |
| (E, L, P, S, C, R, p_recovery, len(ev_rows), now, claim_id), | |
| ) | |
| conn.commit() | |
| return { | |
| "claim_id": claim_id, | |
| "p_recovery": round(p_recovery, 6), | |
| "evidence_strength": round(E, 4), | |
| "counsel_signal": round(L, 4), | |
| "procedural_survival": round(P, 4), | |
| "settlement_signal": round(S, 4), | |
| "contradiction_density": round(C, 4), | |
| "uncertainty": round(R, 4), | |
| "evidence_count": len(ev_rows), | |
| "contradiction_count": len(cx_rows), | |
| "evaluated_at": now, | |
| } | |
| class ContradictionDetector: | |
| """Detects conflicts between evidence sources for a claim. | |
| Uses heuristic scan + optional LLM deep semantic analysis.""" | |
| def detect(cls, claim_id: str, use_llm: bool = True) -> list: | |
| """Scan all evidence pairs for contradictions and persist findings.""" | |
| with _db() as conn: | |
| rows = conn.execute("SELECT * FROM evidence WHERE claim_id = ?", (claim_id,)).fetchall() | |
| contradictions = [] | |
| for i, a in enumerate(rows): | |
| for b in rows[i + 1 :]: | |
| score = cls._scan_pair(a, b) | |
| if score["severity"] > 0.3: | |
| contradictions.append(score) | |
| # Optional LLM deep semantic scan for contradictions not caught by heuristics | |
| if use_llm and len(rows) >= 2: | |
| try: | |
| llm_cx = cls._llm_deep_scan(claim_id, rows) | |
| contradictions.extend(llm_cx) | |
| except Exception as e: | |
| logger.warning(f"LLM deep scan failed for claim {claim_id}: {e}") | |
| # Persist new contradictions | |
| now = datetime.now(timezone.utc).isoformat() | |
| with _db() as conn: | |
| for c in contradictions: | |
| cx_id = f"cx_{uuid.uuid4().hex}" | |
| conn.execute( | |
| """INSERT OR IGNORE INTO contradictions | |
| (contradiction_id, claim_id, evidence_a_id, evidence_b_id, | |
| contradiction_type, severity, description, created_at) | |
| VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", | |
| (cx_id, claim_id, c["evidence_a_id"], c["evidence_b_id"], | |
| c["type"], c["severity"], c["description"], now), | |
| ) | |
| conn.commit() | |
| return contradictions | |
| def _scan_pair(cls, a: sqlite3.Row, b: sqlite3.Row) -> dict: | |
| """Score a single evidence pair for contradiction using heuristics.""" | |
| severity = 0.0 | |
| cx_type = "semantic" | |
| desc = "" | |
| if a["source_type"] == b["source_type"] and a["content_hash"] != b["content_hash"]: | |
| severity = 0.6 | |
| cx_type = "factual" | |
| desc = f"Same source type ({a['source_type']}) with divergent content" | |
| elif a["source_type"] != b["source_type"]: | |
| temporal_a = bool(re.search(r"\b\d{1,2}[/-]\d{1,2}[/-]\d{2,4}\b", a["content"] or "")) | |
| temporal_b = bool(re.search(r"\b\d{1,2}[/-]\d{1,2}[/-]\d{2,4}\b", b["content"] or "")) | |
| if temporal_a and temporal_b: | |
| severity = 0.45 | |
| cx_type = "temporal" | |
| desc = "Both evidence items contain dates β possible temporal conflict" | |
| else: | |
| severity = 0.25 | |
| cx_type = "source" | |
| desc = "Different source types with potential overlap" | |
| else: | |
| severity = 0.1 | |
| desc = "Minor semantic variation" | |
| return { | |
| "evidence_a_id": a["evidence_id"], | |
| "evidence_b_id": b["evidence_id"], | |
| "type": cx_type, | |
| "severity": round(min(1.0, severity), 4), | |
| "description": desc, | |
| } | |
| def _llm_deep_scan(cls, claim_id: str, evidence_rows: list) -> list: | |
| """Use LLM to detect semantic contradictions not visible to regex heuristics.""" | |
| # Build prompt from evidence content | |
| ev_text = "\n\n".join( | |
| f"[{i+1}] {r['source_type'].upper()} (ref: {r['source_ref']}): {r['content'][:800]}" | |
| for i, r in enumerate(evidence_rows) | |
| ) | |
| system_prompt = ( | |
| "You are a legal evidence analyst. Your task is to identify contradictions, conflicts, " | |
| "and inconsistencies between evidence items. Return ONLY a JSON array of contradictions. " | |
| "Each item must have: evidence_a_index (int, 1-based), evidence_b_index (int, 1-based), " | |
| "contradiction_type (one of: temporal, causal, factual, source, semantic), severity (0.0-1.0), " | |
| "description (string). If no contradictions exist, return an empty array []." | |
| ) | |
| user_prompt = f"Analyze the following evidence items for contradictions:\n\n{ev_text}" | |
| try: | |
| result = call_llm(prompt=user_prompt, system=system_prompt, model="json") | |
| parsed = parse_llm_json(result.get("response", "[]")) | |
| if not isinstance(parsed, list): | |
| return [] | |
| llm_cx = [] | |
| for item in parsed: | |
| a_idx = int(item.get("evidence_a_index", 0)) - 1 | |
| b_idx = int(item.get("evidence_b_index", 0)) - 1 | |
| if 0 <= a_idx < len(evidence_rows) and 0 <= b_idx < len(evidence_rows) and a_idx != b_idx: | |
| llm_cx.append({ | |
| "evidence_a_id": evidence_rows[a_idx]["evidence_id"], | |
| "evidence_b_id": evidence_rows[b_idx]["evidence_id"], | |
| "type": str(item.get("contradiction_type", "semantic")).lower(), | |
| "severity": round(min(1.0, max(0.0, float(item.get("severity", 0.5)))), 4), | |
| "description": str(item.get("description", "LLM-detected semantic conflict")), | |
| }) | |
| return llm_cx | |
| except Exception as e: | |
| logger.warning(f"LLM contradiction analysis failed: {e}") | |
| return [] | |
| class ClaimGreeks: | |
| """Compute claim sensitivity metrics (Ξ, Ξ, Ξ, V, K).""" | |
| def compute(cls, claim_id: str) -> dict: | |
| """Compute Greeks for a claim via finite differences.""" | |
| with _db() as conn: | |
| claim = conn.execute("SELECT * FROM claims WHERE claim_id = ?", (claim_id,)).fetchone() | |
| if not claim: | |
| raise ValueError(f"Claim not found: {claim_id}") | |
| base = claim["p_recovery"] or 0.0 | |
| E = claim["evidence_strength"] or 0.0 | |
| C = claim["contradiction_density"] or 0.0 | |
| R = claim["uncertainty"] or 0.0 | |
| eps = ClaimProbabilityEngine.EPS | |
| # Ξclaim = dP/dE | |
| p_plus = ClaimProbabilityEngine._sigmoid((E + eps) + (claim["counsel_signal"] or 0.0) + (claim["procedural_survival"] or 0.0) + (claim["settlement_signal"] or 0.0) - C - R) | |
| p_minus = ClaimProbabilityEngine._sigmoid((E - eps) + (claim["counsel_signal"] or 0.0) + (claim["procedural_survival"] or 0.0) + (claim["settlement_signal"] or 0.0) - C - R) | |
| delta = (p_plus - p_minus) / (2 * eps) | |
| # Ξclaim = dΒ²P/dEΒ² | |
| gamma = (p_plus - 2 * base + p_minus) / (eps * eps) | |
| # Ξclaim = time decay (simplified as -daily_decay * P) | |
| theta = -ClaimProbabilityEngine.TIME_DECAY_DAILY * base | |
| # Vclaim = uncertainty | |
| vega = R | |
| # Kclaim = contradiction drag | |
| kappa = C | |
| now = datetime.now(timezone.utc).isoformat() | |
| with _db() as conn: | |
| conn.execute( | |
| """UPDATE claims SET | |
| delta_claim = ?, theta_claim = ?, gamma_claim = ?, | |
| vega_claim = ?, kappa_claim = ?, updated_at = ? | |
| WHERE claim_id = ?""", | |
| (delta, theta, gamma, vega, kappa, now, claim_id), | |
| ) | |
| conn.commit() | |
| return { | |
| "claim_id": claim_id, | |
| "delta_claim": round(delta, 6), | |
| "theta_claim": round(theta, 6), | |
| "gamma_claim": round(gamma, 6), | |
| "vega_claim": round(vega, 6), | |
| "kappa_claim": round(kappa, 6), | |
| "p_recovery": round(base, 6), | |
| "computed_at": now, | |
| } | |
| class ClaimLiquidity: | |
| """Finance readiness: compute liquidity score from claim state.""" | |
| def compute(cls, claim_id: str) -> dict: | |
| """Compute liquidity score for a claim.""" | |
| with _db() as conn: | |
| claim = conn.execute("SELECT * FROM claims WHERE claim_id = ?", (claim_id,)).fetchone() | |
| if not claim: | |
| raise ValueError(f"Claim not found: {claim_id}") | |
| P = claim["p_recovery"] or 0.0 | |
| E = claim["evidence_strength"] or 0.0 | |
| C = claim["contradiction_density"] or 0.0 | |
| R = claim["uncertainty"] or 0.0 | |
| L = claim["counsel_signal"] or 0.0 | |
| S = claim["settlement_signal"] or 0.0 | |
| # Liquidity_t = Ξ¦(ProofDensity, ProbabilityCompression, CounselRiskCapital, DamageClarity, SettlementSignal) | |
| # - Ξ¨(ContradictionDrag, ProcedureRisk, TimeDecay, EnforcementRisk) | |
| proof_density = E * (1 - C) | |
| probability_compression = P | |
| counsel_capital = L | |
| damage_clarity = E * (1 - R) | |
| settlement_signal = S | |
| contradiction_drag = C * 0.5 | |
| procedure_risk = 1 - (claim["procedural_survival"] or 0.0) | |
| time_decay = ClaimProbabilityEngine.TIME_DECAY_DAILY * 30 # 30-day horizon | |
| enforcement_risk = R * 0.3 | |
| liquidity = ( | |
| (proof_density * 0.25) | |
| + (probability_compression * 0.25) | |
| + (counsel_capital * 0.15) | |
| + (damage_clarity * 0.15) | |
| + (settlement_signal * 0.20) | |
| - (contradiction_drag * 0.30) | |
| - (procedure_risk * 0.20) | |
| - (time_decay * 0.10) | |
| - (enforcement_risk * 0.20) | |
| ) | |
| liquidity = max(0.0, min(1.0, liquidity)) | |
| # Determine finance readiness status | |
| status = claim["status"] | |
| if liquidity >= 0.7 and P >= 0.6: | |
| status = "finance_ready" | |
| elif liquidity >= 0.4 and P >= 0.4: | |
| status = "settlement_signals" | |
| now = datetime.now(timezone.utc).isoformat() | |
| with _db() as conn: | |
| conn.execute( | |
| "UPDATE claims SET liquidity_score = ?, status = ?, updated_at = ? WHERE claim_id = ?", | |
| (liquidity, status, now, claim_id), | |
| ) | |
| conn.commit() | |
| return { | |
| "claim_id": claim_id, | |
| "liquidity_score": round(liquidity, 6), | |
| "p_recovery": round(P, 6), | |
| "status": status, | |
| "components": { | |
| "proof_density": round(proof_density, 4), | |
| "probability_compression": round(probability_compression, 4), | |
| "counsel_capital": round(counsel_capital, 4), | |
| "damage_clarity": round(damage_clarity, 4), | |
| "settlement_signal": round(settlement_signal, 4), | |
| "contradiction_drag": round(contradiction_drag, 4), | |
| "procedure_risk": round(procedure_risk, 4), | |
| "time_decay": round(time_decay, 4), | |
| "enforcement_risk": round(enforcement_risk, 4), | |
| }, | |
| "computed_at": now, | |
| } | |
| # ββ Membra Pixelator / GlyphIndex βββββββββββββββββββββββββββββββ | |
| class MembraPixelator: | |
| """Ingests HTML, tokenizes to glyph units, computes semantic density per character. | |
| All weights and lexicons are loaded from DB β no hardcoded runtime values.""" | |
| def _load_dom_weights(cls) -> dict[str, float]: | |
| with _db() as conn: | |
| rows = conn.execute("SELECT tag, weight FROM dom_weights").fetchall() | |
| return {r["tag"]: r["weight"] for r in rows} if rows else {"p": 1.0} | |
| def _load_lexicon(cls, category: str) -> set[str]: | |
| with _db() as conn: | |
| rows = conn.execute( | |
| "SELECT term FROM semantic_lexicon WHERE category = ? AND confidence >= 0.3", | |
| (category,), | |
| ).fetchall() | |
| return {r["term"] for r in rows} | |
| def ingest(cls, html: str, url: str, website_id: str, title: str = "") -> dict: | |
| """Parse HTML into glyph units and compute page activation.""" | |
| from bs4 import BeautifulSoup | |
| import hashlib | |
| now = datetime.now(timezone.utc).isoformat() | |
| page_id = f"page_{uuid.uuid4().hex[:16]}" | |
| version_id = 1 | |
| soup = BeautifulSoup(html, "html.parser") | |
| page_title = title or (soup.title.string if soup.title else "") | |
| # Strip script/style | |
| for tag in soup(["script", "style", "noscript", "iframe"]): | |
| tag.decompose() | |
| # Extract text blocks with DOM paths | |
| blocks = [] | |
| for elem in soup.find_all(text=True): | |
| parent = elem.parent | |
| if not parent or not elem.strip(): | |
| continue | |
| dom_path = " > ".join([a.name for a in elem.parents if a.name]) + f" > {parent.name}" | |
| text = str(elem).strip() | |
| if text: | |
| blocks.append({"text": text, "dom_path": dom_path, "tag": parent.name}) | |
| # Load learned weights and lexicons from DB (once per ingest) | |
| dom_weights = cls._load_dom_weights() | |
| entity_lex = cls._load_lexicon("entity") | |
| action_lex = cls._load_lexicon("action") | |
| commercial_lex = cls._load_lexicon("commercial") | |
| legal_lex = cls._load_lexicon("legal") | |
| # Paragraph-level tokenization | |
| all_glyphs = [] | |
| paragraph_pos = 0 | |
| total_entity_score = 0.0 | |
| total_action_score = 0.0 | |
| total_commercial_score = 0.0 | |
| total_legal_score = 0.0 | |
| for block in blocks: | |
| text = block["text"] | |
| dom_path = block["dom_path"] | |
| tag = block.get("tag", "span") | |
| dom_weight = dom_weights.get(tag, 0.5) | |
| # Split into sentences (simple heuristic) | |
| sentences = [s.strip() for s in re.split(r'[.!?]+', text) if s.strip()] | |
| for sentence_pos, sentence in enumerate(sentences): | |
| # Tokenize words | |
| tokens = re.findall(r"[A-Za-z]+|[^A-Za-z\s]", sentence) | |
| for token_pos, token in enumerate(tokens): | |
| token_lower = token.lower() | |
| is_entity = token_lower in entity_lex | |
| is_action = token_lower in action_lex | |
| is_commercial = token_lower in commercial_lex | |
| is_legal = token_lower in legal_lex | |
| # Compute per-character scores | |
| for char_index, char in enumerate(token): | |
| char_case = "upper" if char.isupper() else "lower" | |
| # Base semantic density from DOM weight and position | |
| base_density = dom_weight * (1.0 + 0.1 * sentence_pos) | |
| # Capital bonus (entity indicator) | |
| case_bonus = 0.3 if char_case == "upper" else 0.0 | |
| # Proximity scores | |
| entity_prox = 1.0 if is_entity else 0.1 | |
| action_prox = 1.0 if is_action else 0.1 | |
| commercial_prox = 1.0 if is_commercial else 0.1 | |
| legal_prox = 1.0 if is_legal else 0.1 | |
| semantic_density = base_density + case_bonus + (entity_prox * 0.2) + (action_prox * 0.15) | |
| semantic_density = min(10.0, semantic_density) | |
| # Determine roles | |
| if is_entity: | |
| semantic_role = "entity" | |
| activation_role = "signal" | |
| elif is_action: | |
| semantic_role = "action" | |
| activation_role = "event" | |
| elif is_commercial: | |
| semantic_role = "commercial" | |
| activation_role = "value" | |
| elif is_legal: | |
| semantic_role = "legal" | |
| activation_role = "risk" | |
| else: | |
| semantic_role = "body" | |
| activation_role = "neutral" | |
| # Compute proof hash for this glyph | |
| proof_input = f"{page_id}:{paragraph_pos}:{sentence_pos}:{token_pos}:{char_index}:{char}:{now}" | |
| proof_hash = hashlib.sha256(proof_input.encode("utf-8")).hexdigest() | |
| glyph_id = f"glyph_{uuid.uuid4().hex[:12]}" | |
| glyph = { | |
| "glyph_id": glyph_id, | |
| "page_id": page_id, | |
| "website_id": website_id, | |
| "version_id": version_id, | |
| "dom_path": dom_path, | |
| "paragraph_pos": paragraph_pos, | |
| "sentence_pos": sentence_pos, | |
| "token_pos": token_pos, | |
| "char_index": char_index, | |
| "char_value": char, | |
| "char_case": char_case, | |
| "semantic_role": semantic_role, | |
| "activation_role": activation_role, | |
| "proof_hash": proof_hash, | |
| "semantic_density": round(semantic_density, 6), | |
| "glyph_value": 0.0, # computed after page activation | |
| "entity_proximity": round(entity_prox, 4), | |
| "action_proximity": round(action_prox, 4), | |
| "commercial_proximity": round(commercial_prox, 4), | |
| "legal_proximity": round(legal_prox, 4), | |
| "timestamp": now, | |
| } | |
| all_glyphs.append(glyph) | |
| total_entity_score += entity_prox | |
| total_action_score += action_prox | |
| total_commercial_score += commercial_prox | |
| total_legal_score += legal_prox | |
| paragraph_pos += 1 | |
| # Compute page activation value | |
| if all_glyphs: | |
| avg_density = sum(g["semantic_density"] for g in all_glyphs) / len(all_glyphs) | |
| entity_count = sum(1 for g in all_glyphs if g["semantic_role"] == "entity") | |
| action_count = sum(1 for g in all_glyphs if g["semantic_role"] == "action") | |
| else: | |
| avg_density = 0.0 | |
| entity_count = 0 | |
| action_count = 0 | |
| page_activation = avg_density * (1 + 0.01 * entity_count) * (1 + 0.01 * action_count) | |
| page_activation = min(100.0, page_activation) | |
| # Compute final glyph values: GlyphValue = PageActivationValue Γ GlyphContributionWeight | |
| for g in all_glyphs: | |
| contribution_weight = g["semantic_density"] / max(avg_density, 0.001) | |
| g["glyph_value"] = round(page_activation * contribution_weight, 6) | |
| # Persist to database | |
| with _db() as conn: | |
| conn.execute( | |
| """INSERT INTO pages (page_id, website_id, url, title, page_activation_value, | |
| semantic_density, entity_count, action_count, commercial_score, legal_score, | |
| version_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", | |
| (page_id, website_id, url, page_title, round(page_activation, 6), round(avg_density, 6), | |
| entity_count, action_count, round(total_commercial_score, 4), round(total_legal_score, 4), | |
| version_id, now), | |
| ) | |
| for g in all_glyphs: | |
| conn.execute( | |
| """INSERT INTO glyph_units (glyph_id, page_id, website_id, version_id, dom_path, | |
| paragraph_pos, sentence_pos, token_pos, char_index, char_value, char_case, | |
| semantic_role, activation_role, proof_hash, semantic_density, glyph_value, | |
| entity_proximity, action_proximity, commercial_proximity, legal_proximity, timestamp) | |
| VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", | |
| (g["glyph_id"], g["page_id"], g["website_id"], g["version_id"], g["dom_path"], | |
| g["paragraph_pos"], g["sentence_pos"], g["token_pos"], g["char_index"], g["char_value"], | |
| g["char_case"], g["semantic_role"], g["activation_role"], g["proof_hash"], | |
| g["semantic_density"], g["glyph_value"], g["entity_proximity"], g["action_proximity"], | |
| g["commercial_proximity"], g["legal_proximity"], g["timestamp"]), | |
| ) | |
| conn.commit() | |
| return { | |
| "page_id": page_id, | |
| "website_id": website_id, | |
| "url": url, | |
| "title": page_title, | |
| "glyph_count": len(all_glyphs), | |
| "page_activation_value": round(page_activation, 6), | |
| "semantic_density": round(avg_density, 6), | |
| "entity_count": entity_count, | |
| "action_count": action_count, | |
| "version_id": version_id, | |
| "created_at": now, | |
| } | |
| def get_page_glyphs(cls, page_id: str, limit: int = 1000, offset: int = 0) -> list: | |
| """Retrieve glyph units for a page.""" | |
| with _db() as conn: | |
| rows = conn.execute( | |
| """SELECT * FROM glyph_units WHERE page_id = ? | |
| ORDER BY paragraph_pos, sentence_pos, token_pos, char_index | |
| LIMIT ? OFFSET ?""", | |
| (page_id, limit, offset), | |
| ).fetchall() | |
| return [dict(r) for r in rows] | |
| def get_page_activation(cls, page_id: str) -> dict: | |
| """Get page activation summary.""" | |
| with _db() as conn: | |
| page = conn.execute("SELECT * FROM pages WHERE page_id = ?", (page_id,)).fetchone() | |
| if not page: | |
| raise ValueError(f"Page not found: {page_id}") | |
| glyphs = conn.execute( | |
| "SELECT COUNT(*) AS c, AVG(glyph_value) AS avg_val, MAX(glyph_value) AS max_val FROM glyph_units WHERE page_id = ?", | |
| (page_id,), | |
| ).fetchone() | |
| return { | |
| "page": dict(page), | |
| "glyph_count": glyphs["c"], | |
| "avg_glyph_value": round(glyphs["avg_val"] or 0, 6), | |
| "max_glyph_value": round(glyphs["max_val"] or 0, 6), | |
| } | |
| def get_top_glyphs(cls, website_id: str, limit: int = 50) -> list: | |
| """Get highest-value glyphs across a website.""" | |
| with _db() as conn: | |
| rows = conn.execute( | |
| """SELECT * FROM glyph_units WHERE website_id = ? | |
| ORDER BY glyph_value DESC LIMIT ?""", | |
| (website_id, limit), | |
| ).fetchall() | |
| return [dict(r) for r in rows] | |
| def compute_glyph_value(cls, glyph: dict, page_activation: float) -> float: | |
| """Formula: GlyphValue = PageActivationValue Γ GlyphContributionWeight.""" | |
| density = glyph.get("semantic_density", 0.0) | |
| # Contribution weight is normalized semantic density | |
| contribution = density / max(1.0, density) | |
| return round(page_activation * contribution, 6) | |
| # ββ GA-RL Crawler βββββββββββββββββββββββββββββββββββββββββββββββ | |
| class RotatorBuffer: | |
| """Fixed-size ring buffer for crawl queue management.""" | |
| def __init__(self, capacity: int = 100): | |
| self.capacity = capacity | |
| self._buffer = [] | |
| self._head = 0 | |
| self._tail = 0 | |
| self._size = 0 | |
| def push(self, item: dict) -> dict | None: | |
| """Add item; return evicted item if buffer was full.""" | |
| evicted = None | |
| if self._size >= self.capacity: | |
| evicted = self._buffer[self._head] | |
| self._buffer[self._head] = item | |
| self._head = (self._head + 1) % self.capacity | |
| self._tail = (self._tail + 1) % self.capacity | |
| else: | |
| idx = self._tail | |
| if idx < len(self._buffer): | |
| self._buffer[idx] = item | |
| else: | |
| self._buffer.append(item) | |
| self._tail = (self._tail + 1) % self.capacity | |
| self._size += 1 | |
| return evicted | |
| def pop(self) -> dict | None: | |
| """Remove and return oldest item.""" | |
| if self._size == 0: | |
| return None | |
| item = self._buffer[self._head] | |
| self._head = (self._head + 1) % self.capacity | |
| self._size -= 1 | |
| return item | |
| def peek(self) -> dict | None: | |
| if self._size == 0: | |
| return None | |
| return self._buffer[self._head] | |
| def to_list(self) -> list: | |
| if self._size == 0: | |
| return [] | |
| if self._head < self._tail: | |
| return self._buffer[self._head:self._tail] | |
| return self._buffer[self._head:] + self._buffer[:self._tail] | |
| def __len__(self) -> int: | |
| return self._size | |
| class RLPolicy: | |
| """Epsilon-greedy Q-table for website selection.""" | |
| def __init__(self, epsilon: float | None = None, alpha: float | None = None, gamma: float | None = None): | |
| # Load from env; no hardcoded runtime defaults | |
| self.epsilon = epsilon if epsilon is not None else float(os.environ.get("CRAWLER_RL_EPSILON", "0.3")) | |
| self.alpha = alpha if alpha is not None else float(os.environ.get("CRAWLER_RL_ALPHA", "0.1")) | |
| self.gamma = gamma if gamma is not None else float(os.environ.get("CRAWLER_RL_GAMMA", "0.9")) | |
| def select(self, websites: list[dict]) -> dict | None: | |
| """Epsilon-greedy selection from website list.""" | |
| if not websites: | |
| return None | |
| active = [w for w in websites if w.get("is_active", 1)] | |
| if not active: | |
| return None | |
| import random | |
| if random.random() < self.epsilon: | |
| return random.choice(active) | |
| # Greedy: pick highest q_value | |
| best = max(active, key=lambda w: w.get("q_value", 0.0)) | |
| return best | |
| def update(self, website_id: str, reward: float) -> None: | |
| """Q-learning update: Q(s) = Q(s) + alpha * (reward + gamma * maxQ' - Q(s)).""" | |
| with _db() as conn: | |
| row = conn.execute( | |
| "SELECT q_value FROM crawl_policy WHERE website_id = ?", (website_id,) | |
| ).fetchone() | |
| old_q = row["q_value"] if row else 0.0 | |
| # For a single-state problem (just website selection), maxQ' = old_q | |
| new_q = old_q + self.alpha * (reward + self.gamma * old_q - old_q) | |
| new_q = round(new_q, 6) | |
| if row: | |
| conn.execute( | |
| "UPDATE crawl_policy SET q_value = ?, visit_count = visit_count + 1, updated_at = ? WHERE website_id = ?", | |
| (new_q, datetime.now(timezone.utc).isoformat(), website_id), | |
| ) | |
| else: | |
| conn.execute( | |
| """INSERT INTO crawl_policy (policy_id, website_id, q_value, visit_count, epsilon, alpha, gamma, updated_at) | |
| VALUES (?, ?, ?, 1, ?, ?, ?, ?)""", | |
| (f"pol_{uuid.uuid4().hex[:12]}", website_id, new_q, self.epsilon, self.alpha, self.gamma, | |
| datetime.now(timezone.utc).isoformat()), | |
| ) | |
| conn.commit() | |
| class GeneticSelector: | |
| """GA for evolving the target website population based on fitness.""" | |
| def _mutation_rate(cls) -> float: | |
| return float(os.environ.get("CRAWLER_GA_MUTATION", "0.15")) | |
| def _crossover_rate(cls) -> float: | |
| return float(os.environ.get("CRAWLER_GA_CROSSOVER", "0.7")) | |
| def _elite_ratio(cls) -> float: | |
| return float(os.environ.get("CRAWLER_GA_ELITE", "0.2")) | |
| def fitness(cls, target: dict) -> float: | |
| """Fitness = avg_glyph_value * success_rate * log(crawl_count + 1).""" | |
| avg_gv = target.get("avg_glyph_value", 0.0) | |
| crawls = max(target.get("crawl_count", 1), 1) | |
| successes = target.get("success_count", 0) | |
| success_rate = successes / crawls | |
| return avg_gv * success_rate * (1 + 0.1 * math.log(crawls + 1)) | |
| def evolve(cls, population: list[dict], generation: int = 0) -> list[dict]: | |
| """Run one generation of selection + crossover + mutation.""" | |
| import random | |
| if len(population) < 4: | |
| return population | |
| # Sort by fitness descending | |
| scored = [(t, cls.fitness(t)) for t in population] | |
| scored.sort(key=lambda x: x[1], reverse=True) | |
| # Elitism: keep top performers | |
| elite_count = max(1, int(len(scored) * cls._elite_ratio())) | |
| new_pop = [dict(s[0]) for s in scored[:elite_count]] | |
| # Generate offspring via crossover + mutation | |
| while len(new_pop) < len(population): | |
| p1, p2 = random.choices(scored, weights=[max(s[1], 0.01) for s in scored], k=2) | |
| child = cls._crossover(p1[0], p2[0]) | |
| child = cls._mutate(child, generation) | |
| child["fitness_score"] = round(cls.fitness(child), 6) | |
| new_pop.append(child) | |
| return new_pop[:len(population)] | |
| def _crossover(cls, a: dict, b: dict) -> dict: | |
| import random | |
| child = dict(a) | |
| if random.random() < cls._crossover_rate(): | |
| # Blend priority and crawl_depth | |
| child["priority"] = round((a.get("priority", 1.0) + b.get("priority", 1.0)) / 2, 4) | |
| child["crawl_depth"] = max(1, int((a.get("crawl_depth", 2) + b.get("crawl_depth", 2)) / 2)) | |
| return child | |
| def _mutate(cls, child: dict, generation: int) -> dict: | |
| import random | |
| if random.random() < cls._mutation_rate(): | |
| delta = random.uniform(-0.5, 0.5) | |
| child["priority"] = round(max(0.1, child.get("priority", 1.0) + delta), 4) | |
| if random.random() < cls._mutation_rate(): | |
| delta = random.randint(-1, 1) | |
| child["crawl_depth"] = max(1, min(5, child.get("crawl_depth", 2) + delta)) | |
| child["generation"] = generation | |
| return child | |
| class GARLCrawler: | |
| """Genetic Algorithm + Reinforcement Learning web crawler with rotator buffer.""" | |
| def __init__(self, buffer_capacity: int = 200): | |
| self.buffer = RotatorBuffer(capacity=buffer_capacity) | |
| self.policy = RLPolicy() | |
| self.selector = GeneticSelector() | |
| self._gen_count = 0 | |
| def add_target(self, website_id: str, root_url: str, name: str = "", depth: int = 2, priority: float = 1.0, selector_rules: str = "") -> dict: | |
| """Register a new crawl target website.""" | |
| now = datetime.now(timezone.utc).isoformat() | |
| target_id = f"target_{uuid.uuid4().hex[:12]}" | |
| with _db() as conn: | |
| try: | |
| conn.execute( | |
| """INSERT INTO crawl_targets (target_id, website_id, root_url, name, priority, crawl_depth, selector_rules, is_active, created_at) | |
| VALUES (?, ?, ?, ?, ?, ?, ?, 1, ?)""", | |
| (target_id, website_id, root_url, name or website_id, priority, depth, selector_rules or "", now), | |
| ) | |
| # Ensure policy row exists | |
| conn.execute( | |
| """INSERT OR IGNORE INTO crawl_policy (policy_id, website_id, q_value, epsilon, alpha, gamma, updated_at) | |
| VALUES (?, ?, 0.0, ?, ?, ?, ?)""", | |
| (f"pol_{uuid.uuid4().hex[:12]}", website_id, self.policy.epsilon, self.policy.alpha, self.policy.gamma, now), | |
| ) | |
| conn.commit() | |
| except sqlite3.IntegrityError: | |
| raise ValueError(f"Website already exists: {website_id}") | |
| return {"target_id": target_id, "website_id": website_id, "root_url": root_url} | |
| def enqueue(self, target_id: str, url: str, depth: int = 0, priority_score: float = 0.0) -> dict: | |
| """Add URL to rotator buffer and DB queue.""" | |
| queue_id = f"q_{uuid.uuid4().hex[:12]}" | |
| now = datetime.now(timezone.utc).isoformat() | |
| item = {"queue_id": queue_id, "target_id": target_id, "url": url, "depth": depth, | |
| "priority_score": priority_score, "status": "pending", "added_at": now} | |
| evicted = self.buffer.push(item) | |
| with _db() as conn: | |
| conn.execute( | |
| """INSERT INTO crawl_queue (queue_id, target_id, url, status, priority_score, q_value, depth, added_at) | |
| VALUES (?, ?, ?, 'pending', ?, ?, ?, ?)""", | |
| (queue_id, target_id, url, priority_score, priority_score, depth, now), | |
| ) | |
| conn.commit() | |
| return {"queue_id": queue_id, "evicted": evicted} | |
| def select_next(self) -> dict | None: | |
| """RL-based selection: pick a website, then pop oldest pending URL from buffer.""" | |
| with _db() as conn: | |
| rows = conn.execute("SELECT * FROM crawl_targets WHERE is_active = 1").fetchall() | |
| websites = [dict(r) for r in rows] | |
| selected_website = self.policy.select(websites) | |
| if not selected_website: | |
| return None | |
| # Find oldest pending item for this website in buffer | |
| for item in self.buffer.to_list(): | |
| if item.get("status") == "pending": | |
| # Match by target_id | |
| target_id = item.get("target_id") | |
| # Verify this target belongs to selected website | |
| with _db() as conn: | |
| t = conn.execute("SELECT website_id FROM crawl_targets WHERE target_id = ?", (target_id,)).fetchone() | |
| if t and t["website_id"] == selected_website["website_id"]: | |
| return item | |
| # If no buffered item, try DB queue | |
| with _db() as conn: | |
| row = conn.execute( | |
| """SELECT * FROM crawl_queue WHERE target_id IN | |
| (SELECT target_id FROM crawl_targets WHERE website_id = ?) | |
| AND status = 'pending' ORDER BY added_at LIMIT 1""", | |
| (selected_website["website_id"],), | |
| ).fetchone() | |
| if row: | |
| return dict(row) | |
| return None | |
| def ingest_url(self, url: str, target_id: str, queue_id: str, wallet: str = "") -> dict: | |
| """Fetch URL, pixelate HTML, record result, update RL reward.""" | |
| import time | |
| import urllib.request | |
| start_ms = int(time.time() * 1000) | |
| now = datetime.now(timezone.utc).isoformat() | |
| result_id = f"res_{uuid.uuid4().hex[:12]}" | |
| try: | |
| # Simple fetch with timeout | |
| req = urllib.request.Request(url, headers={"User-Agent": "MembraBot/1.0"}) | |
| with urllib.request.urlopen(req, timeout=15) as resp: | |
| html = resp.read().decode("utf-8", errors="replace") | |
| final_url = resp.geturl() | |
| except Exception as e: | |
| with _db() as conn: | |
| conn.execute( | |
| "UPDATE crawl_queue SET status = 'failed', error_msg = ?, completed_at = ? WHERE queue_id = ?", | |
| (str(e), now, queue_id), | |
| ) | |
| conn.execute( | |
| """INSERT INTO crawl_results (result_id, queue_id, target_id, page_id, url, status, reward, crawled_at) | |
| VALUES (?, ?, ?, ?, ?, 'failed', 0.0, ?)""", | |
| (result_id, queue_id, target_id, "", url, now), | |
| ) | |
| conn.commit() | |
| return {"status": "failed", "error": str(e), "url": url} | |
| # Get website_id | |
| with _db() as conn: | |
| trow = conn.execute("SELECT website_id FROM crawl_targets WHERE target_id = ?", (target_id,)).fetchone() | |
| website_id = trow["website_id"] if trow else "unknown" | |
| # Pixelate | |
| px_result = MembraPixelator.ingest(html, final_url, website_id) | |
| page_id = px_result["page_id"] | |
| reward = px_result.get("page_activation_value", 0.0) + (px_result.get("glyph_count", 0) * 0.001) | |
| reward = round(reward, 6) | |
| elapsed = int(time.time() * 1000) - start_ms | |
| with _db() as conn: | |
| conn.execute( | |
| "UPDATE crawl_queue SET status = 'completed', page_id = ?, reward = ?, completed_at = ? WHERE queue_id = ?", | |
| (page_id, reward, now, queue_id), | |
| ) | |
| conn.execute( | |
| """INSERT INTO crawl_results (result_id, queue_id, target_id, page_id, url, status, glyph_count, | |
| page_activation, avg_glyph_value, reward, crawl_time_ms, crawled_at) | |
| VALUES (?, ?, ?, ?, ?, 'completed', ?, ?, ?, ?, ?, ?)""", | |
| (result_id, queue_id, target_id, page_id, final_url, px_result.get("glyph_count", 0), | |
| px_result.get("page_activation_value", 0.0), px_result.get("semantic_density", 0.0), | |
| reward, elapsed, now), | |
| ) | |
| # Update target stats | |
| conn.execute( | |
| """UPDATE crawl_targets SET crawl_count = crawl_count + 1, success_count = success_count + 1, | |
| last_crawled = ?, avg_glyph_value = | |
| (avg_glyph_value * (crawl_count) + ?) / (crawl_count + 1) | |
| WHERE target_id = ?""", | |
| (now, px_result.get("semantic_density", 0.0), target_id), | |
| ) | |
| conn.commit() | |
| # RL update | |
| self.policy.update(website_id, reward) | |
| return { | |
| "status": "completed", | |
| "url": final_url, | |
| "page_id": page_id, | |
| "glyph_count": px_result.get("glyph_count"), | |
| "page_activation": px_result.get("page_activation_value"), | |
| "reward": reward, | |
| "crawl_time_ms": elapsed, | |
| } | |
| def run_evolution(self) -> dict: | |
| """Run one GA generation on active targets.""" | |
| with _db() as conn: | |
| rows = conn.execute("SELECT * FROM crawl_targets WHERE is_active = 1").fetchall() | |
| population = [dict(r) for r in rows] | |
| self._gen_count += 1 | |
| evolved = self.selector.evolve(population, generation=self._gen_count) | |
| with _db() as conn: | |
| for target in evolved: | |
| conn.execute( | |
| "UPDATE crawl_targets SET priority = ?, fitness_score = ?, crawl_depth = ? WHERE target_id = ?", | |
| (target.get("priority", 1.0), target.get("fitness_score", 0.0), target.get("crawl_depth", 2), target.get("target_id")), | |
| ) | |
| conn.execute( | |
| "UPDATE crawl_policy SET generation = ? WHERE generation < ?", | |
| (self._gen_count, self._gen_count), | |
| ) | |
| conn.commit() | |
| return {"generation": self._gen_count, "population_size": len(evolved)} | |
| def get_queue(self, limit: int = 100) -> list: | |
| with _db() as conn: | |
| rows = conn.execute( | |
| "SELECT * FROM crawl_queue ORDER BY added_at DESC LIMIT ?", (limit,) | |
| ).fetchall() | |
| return [dict(r) for r in rows] | |
| def get_results(self, website_id: str | None = None, limit: int = 100) -> list: | |
| with _db() as conn: | |
| if website_id: | |
| rows = conn.execute( | |
| "SELECT * FROM crawl_results WHERE target_id IN (SELECT target_id FROM crawl_targets WHERE website_id = ?) ORDER BY crawled_at DESC LIMIT ?", | |
| (website_id, limit), | |
| ).fetchall() | |
| else: | |
| rows = conn.execute( | |
| "SELECT * FROM crawl_results ORDER BY crawled_at DESC LIMIT ?", (limit,) | |
| ).fetchall() | |
| return [dict(r) for r in rows] | |
| def get_policy(self) -> list: | |
| with _db() as conn: | |
| rows = conn.execute( | |
| "SELECT * FROM crawl_policy ORDER BY q_value DESC" | |
| ).fetchall() | |
| return [dict(r) for r in rows] | |
| # ββ Wallet Signature Verification ββββββββββββββββββββββββββββββββ | |
| def _verify_evm_signature(address: str, signature: str, nonce: str) -> bool: | |
| try: | |
| from eth_account import Account | |
| from eth_account.messages import encode_defunct | |
| message = f"HF VM Studio auth: {nonce}" | |
| encoded = encode_defunct(text=message) | |
| recovered = Account.recover_message(encoded, signature_bytes=bytes.fromhex(signature.removeprefix("0x"))) | |
| return recovered.lower() == address.lower() | |
| except Exception as e: | |
| logger.warning(f"EVM signature verification failed: {e}") | |
| return False | |
| def _verify_solana_signature(address: str, signature: str, nonce: str) -> bool: | |
| try: | |
| import nacl.signing | |
| import nacl.exceptions | |
| import base64 | |
| import base58 | |
| message = f"HF VM Studio auth: {nonce}".encode("utf-8") | |
| # Decode address from base58 (Solana public key format) | |
| pub_key_bytes = base58.b58decode(address) | |
| # Signature may be base58 or base64 encoded | |
| try: | |
| sig_bytes = base58.b58decode(signature) | |
| except Exception: | |
| sig_bytes = base64.b64decode(signature) | |
| verify_key = nacl.signing.VerifyKey(pub_key_bytes) | |
| verify_key.verify(message, sig_bytes) | |
| return True | |
| except nacl.exceptions.BadSignatureError: | |
| return False | |
| except Exception as e: | |
| logger.warning(f"Solana signature verification failed: {e}") | |
| return False | |
| def _nonce() -> str: | |
| return hashlib.sha256(os.urandom(32)).hexdigest()[:24] | |
| # ββ Rate Limiting ββββββββββββββββββββββββββββββββββββββββββββββ | |
| _rate_buckets: Dict[str, list] = {} | |
| _rate_lock = threading.RLock() | |
| def _rate_check(key: str, window: int = 60, max_requests: int = 30) -> bool: | |
| now = time.time() | |
| with _rate_lock: | |
| # Periodic cleanup: purge stale keys every ~1000 calls | |
| if len(_rate_buckets) > 2000 and hash(key) % 100 == 0: | |
| stale = [k for k, v in _rate_buckets.items() if v and now - v[-1] > window * 2] | |
| for k in stale: | |
| del _rate_buckets[k] | |
| bucket = _rate_buckets.get(key, []) | |
| bucket = [t for t in bucket if now - t < window] | |
| if len(bucket) >= max_requests: | |
| return False | |
| bucket.append(now) | |
| _rate_buckets[key] = bucket | |
| return True | |
| def rate_limit_response(): | |
| return jsonify({"error": "Rate limit exceeded. Slow down."}), 429 | |
| # ββ Helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def save_state(): | |
| state["last_check"] = datetime.now(timezone.utc).isoformat() | |
| with open(STATE_PATH, "w") as f: | |
| json.dump(state, f, indent=2) | |
| def load_config(): | |
| global tasks | |
| if CONFIG_PATH.exists(): | |
| with open(CONFIG_PATH) as f: | |
| tasks = json.load(f).get("tasks", {}) | |
| else: | |
| tasks = {} | |
| CONFIG_PATH.write_text(json.dumps({"tasks": {}}, indent=2)) | |
| def load_memory(): | |
| global memories | |
| if MEMORY_PATH.exists(): | |
| try: | |
| memories = json.loads(MEMORY_PATH.read_text()).get("memories", {}) | |
| except Exception: | |
| logger.exception("Failed to load memory store") | |
| memories = {} | |
| else: | |
| memories = {} | |
| save_memory() | |
| def save_memory(): | |
| with memory_lock: | |
| MEMORY_PATH.write_text(json.dumps({"memories": memories}, indent=2)) | |
| def load_apps(): | |
| global apps | |
| if APPS_PATH.exists(): | |
| try: | |
| raw = json.loads(APPS_PATH.read_text()).get("apps", {}) | |
| apps = {} | |
| for app_id, item in raw.items(): | |
| item["_popen"] = None | |
| item["status"] = "stopped" | |
| item.setdefault("stdout", "") | |
| item.setdefault("stderr", "") | |
| apps[app_id] = item | |
| except Exception: | |
| logger.exception("Failed to load generated apps") | |
| apps = {} | |
| else: | |
| apps = {} | |
| save_apps() | |
| def save_apps(): | |
| with app_lock: | |
| serializable = {} | |
| for app_id, item in apps.items(): | |
| serializable[app_id] = {k: v for k, v in item.items() if k != "_popen"} | |
| APPS_PATH.write_text(json.dumps({"apps": serializable}, indent=2)) | |
| def load_receipts(): | |
| global receipts | |
| if RECEIPTS_PATH.exists(): | |
| try: | |
| receipts = json.loads(RECEIPTS_PATH.read_text()).get("receipts", {}) | |
| except Exception: | |
| logger.exception("Failed to load receipts store") | |
| receipts = {} | |
| else: | |
| receipts = {} | |
| save_receipts() | |
| def save_receipts(): | |
| with receipt_lock: | |
| RECEIPTS_PATH.write_text(json.dumps({"receipts": receipts}, indent=2)) | |
| def default_settings() -> dict: | |
| default_api_base = os.environ.get("LLM_API_BASE", "https://api.openai.com/v1") | |
| default_model = os.environ.get("LLM_MODEL", "gpt-4o-mini") | |
| if os.environ.get("GROQ_API_KEY"): | |
| default_api_base = "https://api.groq.com/openai/v1" | |
| default_model = os.environ.get("LLM_MODEL", "llama-3.1-8b-instant") | |
| elif os.environ.get("OPENROUTER_API_KEY"): | |
| default_api_base = "https://openrouter.ai/api/v1" | |
| default_model = os.environ.get("LLM_MODEL", "openai/gpt-4o-mini") | |
| return { | |
| "cwd": str(DEFAULT_CWD), | |
| "max_timeout": MAX_COMMAND_TIMEOUT, | |
| "env": {}, | |
| "llm": { | |
| "api_base": default_api_base, | |
| "model": default_model, | |
| }, | |
| "deploy": { | |
| "vercel_project_dir": "/app", | |
| "netlify_project_dir": "/app", | |
| "netlify_publish_dir": "/app", | |
| }, | |
| } | |
| def load_settings(): | |
| global settings | |
| if SETTINGS_PATH.exists(): | |
| try: | |
| loaded = json.loads(SETTINGS_PATH.read_text()) | |
| base = default_settings() | |
| base.update({k: v for k, v in loaded.items() if isinstance(v, dict) or k in {"cwd", "max_timeout"}}) | |
| base["env"].update(loaded.get("env", {})) | |
| base["llm"].update(loaded.get("llm", {})) | |
| base["deploy"].update(loaded.get("deploy", {})) | |
| settings = base | |
| except Exception: | |
| logger.exception("Failed to load settings") | |
| settings = default_settings() | |
| else: | |
| settings = default_settings() | |
| save_settings() | |
| def save_settings(): | |
| with settings_lock: | |
| SETTINGS_PATH.write_text(json.dumps(settings, indent=2)) | |
| def redacted_settings() -> dict: | |
| with settings_lock: | |
| data = json.loads(json.dumps(settings)) | |
| redacted_env = {} | |
| for key, value in data.get("env", {}).items(): | |
| if any(word in key.upper() for word in ["TOKEN", "KEY", "SECRET", "PASSWORD"]): | |
| redacted_env[key] = {"configured": bool(value), "redacted": True} | |
| else: | |
| redacted_env[key] = value | |
| data["env"] = redacted_env | |
| return data | |
| def runtime_env(extra: Optional[dict] = None) -> dict: | |
| env = os.environ.copy() | |
| env.update({k: str(v) for k, v in settings.get("env", {}).items() if v is not None}) | |
| if extra: | |
| env.update({k: str(v) for k, v in extra.items() if v is not None}) | |
| return env | |
| def runtime_cwd(cwd: Optional[str] = None) -> str: | |
| return cwd or settings.get("cwd") or str(DEFAULT_CWD) | |
| def add_memory( | |
| title: str, | |
| content: str, | |
| source: str = "manual", | |
| tags: Optional[list] = None, | |
| metadata: Optional[dict] = None, | |
| importance: float = 0.5, | |
| ) -> dict: | |
| with memory_lock: | |
| memory_id = f"mem_{uuid.uuid4().hex[:16]}" | |
| item = { | |
| "memory_id": memory_id, | |
| "title": title[:240], | |
| "content": content[:20000], | |
| "source": source, | |
| "tags": tags or [], | |
| "metadata": metadata or {}, | |
| "importance": max(0.0, min(float(importance), 1.0)), | |
| "created_at": datetime.now(timezone.utc).isoformat(), | |
| "access_count": 0, | |
| "tombstone_at": None, | |
| } | |
| memories[memory_id] = item | |
| save_memory() | |
| return item | |
| def memory_text(memory: dict) -> str: | |
| return " ".join([ | |
| memory.get("title", ""), | |
| memory.get("content", ""), | |
| " ".join(memory.get("tags", [])), | |
| json.dumps(memory.get("metadata", {}), sort_keys=True), | |
| ]).lower() | |
| def search_memory(query: str, limit: int = 8) -> list: | |
| terms = [term for term in query.lower().split() if term] | |
| with memory_lock: | |
| results = [] | |
| for memory in memories.values(): | |
| if memory.get("tombstone_at"): | |
| continue | |
| text = memory_text(memory) | |
| matches = sum(text.count(term) for term in terms) if terms else 1 | |
| if matches <= 0: | |
| continue | |
| score = matches + memory.get("importance", 0.5) + memory.get("access_count", 0) * 0.05 | |
| result = dict(memory) | |
| result["score"] = round(score, 4) | |
| results.append(result) | |
| results.sort(key=lambda item: item["score"], reverse=True) | |
| results = results[:limit] | |
| for result in results: | |
| memories[result["memory_id"]]["access_count"] += 1 | |
| if results: | |
| save_memory() | |
| return results | |
| def sha256_text(value: str) -> str: | |
| return hashlib.sha256(value.encode("utf-8", errors="replace")).hexdigest() | |
| def redact_command_secret(command: str, secret: str = "") -> str: | |
| if secret: | |
| return command.replace(secret, "[redacted]") | |
| return command | |
| def app_file_manifest(app_record: dict) -> list: | |
| manifest = [] | |
| app_dir = Path(app_record.get("path", "")) | |
| for file_name in app_record.get("files", []): | |
| try: | |
| file_path = safe_app_file(app_dir, file_name) | |
| content = file_path.read_text() if file_path.exists() else "" | |
| manifest.append({ | |
| "path": file_name, | |
| "sha256": sha256_text(content), | |
| "bytes": len(content.encode("utf-8", errors="replace")), | |
| }) | |
| except Exception as e: | |
| manifest.append({"path": file_name, "error": str(e)}) | |
| return manifest | |
| def create_receipt( | |
| kind: str, | |
| title: str, | |
| status: str = "recorded", | |
| prompt: str = "", | |
| app_record: Optional[dict] = None, | |
| model: Optional[dict] = None, | |
| command: str = "", | |
| process: Optional[dict] = None, | |
| deployment: Optional[dict] = None, | |
| metadata: Optional[dict] = None, | |
| ) -> dict: | |
| """Create a cryptographically-verifiable receipt. Receipt ID is SHA-256 of payload.""" | |
| prompt = prompt or "" | |
| app_copy = redact_app(app_record) if app_record else None | |
| manifest = app_file_manifest(app_copy) if app_copy else [] | |
| now = datetime.now(timezone.utc).isoformat() | |
| # Build payload without receipt_id so hash is deterministic | |
| payload = { | |
| "kind": kind, | |
| "title": title[:240], | |
| "status": status, | |
| "created_at": now, | |
| "prompt_hash": sha256_text(prompt) if prompt else None, | |
| "prompt_excerpt": prompt[:1200] if prompt else "", | |
| "model": model or {}, | |
| "app": app_copy, | |
| "app_id": app_copy.get("app_id") if app_copy else None, | |
| "proxy_url": app_copy.get("proxy_url") if app_copy else None, | |
| "files": manifest, | |
| "files_hash": sha256_text(json.dumps(manifest, sort_keys=True)) if manifest else None, | |
| "command": command, | |
| "process": redact_process(process) if process else {}, | |
| "deployment": deployment or {}, | |
| "metadata": metadata or {}, | |
| } | |
| # Cryptographic receipt ID: SHA-256 of canonical JSON payload | |
| payload_bytes = json.dumps(payload, sort_keys=True, ensure_ascii=True).encode("utf-8") | |
| receipt_hash = hashlib.sha256(payload_bytes).hexdigest() | |
| receipt_id = f"rcpt_{receipt_hash[:32]}" | |
| receipt = {"receipt_id": receipt_id, **payload} | |
| with receipt_lock: | |
| receipts[receipt_id] = receipt | |
| save_receipts() | |
| memory = add_memory( | |
| title=f"Receipt: {title[:100]}", | |
| content=json.dumps(receipt, indent=2), | |
| source="receipt", | |
| tags=["receipt", kind, "provenance"], | |
| metadata={"receipt_id": receipt_id, "app_id": receipt.get("app_id")}, | |
| importance=0.9, | |
| ) | |
| receipt["memory_id"] = memory["memory_id"] | |
| with receipt_lock: | |
| receipts[receipt_id] = receipt | |
| save_receipts() | |
| return receipt | |
| def attach_receipt_to_app(app_id: str, receipt_id: str): | |
| with app_lock: | |
| if app_id in apps: | |
| apps[app_id]["receipt_id"] = receipt_id | |
| save_apps() | |
| def receipt_text(receipt: dict) -> str: | |
| return json.dumps(receipt, sort_keys=True).lower() | |
| def search_receipts(query: str, limit: int = 20) -> list: | |
| terms = [term for term in query.lower().split() if term] | |
| with receipt_lock: | |
| results = [] | |
| for receipt in receipts.values(): | |
| text = receipt_text(receipt) | |
| matches = sum(text.count(term) for term in terms) if terms else 1 | |
| if matches <= 0: | |
| continue | |
| item = dict(receipt) | |
| item["score"] = matches | |
| results.append(item) | |
| results.sort(key=lambda item: (item["score"], item.get("created_at", "")), reverse=True) | |
| return results[:limit] | |
| def get_uptime() -> str: | |
| if not state.get("start_time"): | |
| return "N/A" | |
| start = datetime.fromisoformat(state["start_time"]) | |
| uptime = datetime.now(timezone.utc) - start | |
| return f"{uptime.days}d {uptime.seconds // 3600}h {(uptime.seconds % 3600) // 60}m" | |
| def bounded_timeout(value, default=60) -> int: | |
| try: | |
| timeout = int(value) | |
| except Exception: | |
| timeout = default | |
| configured_max = int(settings.get("max_timeout", MAX_COMMAND_TIMEOUT)) if settings else MAX_COMMAND_TIMEOUT | |
| return max(1, min(timeout, configured_max)) | |
| def generate_inference_proof( | |
| model: str, | |
| prompt: str, | |
| response: str, | |
| provider: str, | |
| api_base: str, | |
| latency_ms: float, | |
| input_tokens: int, | |
| output_tokens: int, | |
| ) -> dict: | |
| """Generate a cryptographically verifiable Proof of Inference (PoI). | |
| Every LLM call gets a SHA-256 receipt of its inputs and outputs. | |
| """ | |
| now = datetime.now(timezone.utc).isoformat() | |
| payload = { | |
| "model": model, | |
| "provider": provider, | |
| "api_base": api_base, | |
| "prompt_hash": hashlib.sha256(prompt.encode("utf-8")).hexdigest(), | |
| "response_hash": hashlib.sha256(response.encode("utf-8")).hexdigest(), | |
| "latency_ms": latency_ms, | |
| "input_tokens": input_tokens, | |
| "output_tokens": output_tokens, | |
| "timestamp": now, | |
| } | |
| payload_bytes = json.dumps(payload, sort_keys=True, ensure_ascii=True).encode("utf-8") | |
| proof_hash = hashlib.sha256(payload_bytes).hexdigest() | |
| proof_id = f"poi_{proof_hash[:32]}" | |
| return { | |
| "proof_id": proof_id, | |
| "proof_hash": proof_hash, | |
| "prompt_hash": payload["prompt_hash"], | |
| "response_hash": payload["response_hash"], | |
| "timestamp": now, | |
| "verified": True, | |
| } | |
| def _reward_idempotency_key(wallet: str, action: str, amount: int, data: dict) -> str: | |
| """Deterministic idempotency key based on wallet + action + request payload hash.""" | |
| payload_fields = ["command", "code", "prompt", "cells", "task", "mode"] | |
| core = json.dumps({k: data.get(k) for k in payload_fields if data.get(k)}, sort_keys=True, separators=(",", ":")) | |
| if not core: | |
| core = json.dumps(data, sort_keys=True, separators=(",", ":")) | |
| h = hashlib.sha256(f"{wallet}:{action}:{amount}:{core}".encode("utf-8")).hexdigest()[:20] | |
| return f"reward_{h}" | |
| def maybe_credit(data: dict, action: str, amount: int) -> Optional[dict]: | |
| """Credit tokens if wallet_address is present in request data. Idempotent via content hash.""" | |
| raw = str(data.get("wallet_address", "")).strip() | |
| wallet = _normalize_wallet(raw) if raw else "" | |
| if wallet: | |
| ikey = data.get("idempotency_key") or _reward_idempotency_key(wallet, action, amount, data) | |
| return credit_tokens(wallet, amount, action, idempotency_key=ikey) | |
| return None | |
| def run_command(cmd: str, timeout: int = 60, cwd: Optional[str] = None) -> dict: | |
| timeout = bounded_timeout(timeout) | |
| cwd_path = runtime_cwd(cwd) | |
| logger.info(f"Executing: {cmd}") | |
| try: | |
| result = subprocess.run( | |
| cmd, | |
| shell=True, | |
| capture_output=True, | |
| text=True, | |
| timeout=timeout, | |
| cwd=cwd_path, | |
| env=runtime_env(), | |
| ) | |
| return { | |
| "exit_code": result.returncode, | |
| "stdout": result.stdout, | |
| "stderr": result.stderr, | |
| "success": result.returncode == 0, | |
| "cwd": cwd_path, | |
| } | |
| except subprocess.TimeoutExpired: | |
| return {"exit_code": -1, "stdout": "", "stderr": "Command timed out", "success": False, "cwd": cwd_path} | |
| except Exception as e: | |
| return {"exit_code": -1, "stdout": "", "stderr": str(e), "success": False, "cwd": cwd_path} | |
| def is_authorized() -> bool: | |
| if not TERMINAL_AGENT_TOKEN: | |
| return False | |
| token = ( | |
| request.headers.get("x-terminal-token") | |
| or request.headers.get("authorization", "").replace("Bearer ", "", 1) | |
| or request.args.get("token", "") | |
| ) | |
| return token == TERMINAL_AGENT_TOKEN | |
| def require_auth(): | |
| if not is_authorized(): | |
| return jsonify({"error": "Unauthorized"}), 401 | |
| return None | |
| def redact_process(proc: dict) -> dict: | |
| return {k: v for k, v in proc.items() if k != "_popen"} | |
| def launch_background_process(cmd: str, timeout: int = 0, cwd: Optional[str] = None) -> dict: | |
| process_id = f"proc_{uuid.uuid4().hex[:16]}" | |
| cwd_path = runtime_cwd(cwd) | |
| proc = subprocess.Popen( | |
| cmd, | |
| shell=True, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.PIPE, | |
| text=True, | |
| cwd=cwd_path, | |
| env=runtime_env(), | |
| preexec_fn=os.setsid if hasattr(os, "setsid") else None, | |
| ) | |
| record = { | |
| "process_id": process_id, | |
| "pid": proc.pid, | |
| "command": cmd, | |
| "cwd": cwd_path, | |
| "status": "running", | |
| "started_at": datetime.now(timezone.utc).isoformat(), | |
| "finished_at": None, | |
| "exit_code": None, | |
| "stdout": "", | |
| "stderr": "", | |
| "_popen": proc, | |
| } | |
| processes[process_id] = record | |
| def waiter(): | |
| try: | |
| wait_timeout = bounded_timeout(timeout) if timeout else None | |
| stdout, stderr = proc.communicate(timeout=wait_timeout) | |
| record.update({ | |
| "status": "finished", | |
| "finished_at": datetime.now(timezone.utc).isoformat(), | |
| "exit_code": proc.returncode, | |
| "stdout": stdout, | |
| "stderr": stderr, | |
| }) | |
| add_memory( | |
| title=f"Background command: {cmd[:80]}", | |
| content=f"command: {cmd}\nstdout:\n{stdout}\nstderr:\n{stderr}", | |
| source="background", | |
| tags=["process", "terminal"], | |
| metadata={"process_id": process_id, "exit_code": proc.returncode, "cwd": cwd_path}, | |
| importance=0.55, | |
| ) | |
| except subprocess.TimeoutExpired: | |
| try: | |
| if hasattr(os, "killpg"): | |
| os.killpg(os.getpgid(proc.pid), signal.SIGTERM) | |
| else: | |
| proc.terminate() | |
| except Exception: | |
| pass | |
| stdout, stderr = proc.communicate() | |
| record.update({ | |
| "status": "timeout", | |
| "finished_at": datetime.now(timezone.utc).isoformat(), | |
| "exit_code": proc.returncode, | |
| "stdout": stdout, | |
| "stderr": stderr + "\nProcess timed out", | |
| }) | |
| add_memory( | |
| title=f"Background timeout: {cmd[:80]}", | |
| content=f"command: {cmd}\nstdout:\n{stdout}\nstderr:\n{stderr}\nProcess timed out", | |
| source="background", | |
| tags=["process", "timeout"], | |
| metadata={"process_id": process_id, "exit_code": proc.returncode, "cwd": cwd_path}, | |
| importance=0.65, | |
| ) | |
| threading.Thread(target=waiter, daemon=True).start() | |
| return redact_process(record) | |
| def redact_app(item: dict) -> dict: | |
| return {k: v for k, v in item.items() if k != "_popen"} | |
| def slugify(value: str) -> str: | |
| slug = re.sub(r"[^a-zA-Z0-9_-]+", "-", value.strip().lower()).strip("-") | |
| return slug[:48] or f"app-{uuid.uuid4().hex[:8]}" | |
| def next_app_port() -> int: | |
| used = {int(item.get("port", 0)) for item in apps.values() if item.get("port")} | |
| port = 9000 | |
| while port in used: | |
| port += 1 | |
| return port | |
| def safe_app_file(app_dir: Path, rel_path: str) -> Path: | |
| rel = Path(str(rel_path).strip().lstrip("/")) | |
| target = (app_dir / rel).resolve() | |
| root = app_dir.resolve() | |
| if root != target and root not in target.parents: | |
| raise ValueError(f"Unsafe file path: {rel_path}") | |
| return target | |
| def create_generated_app(data: dict) -> dict: | |
| name = str(data.get("name") or "generated-backend") | |
| app_id = f"{slugify(name)}-{uuid.uuid4().hex[:6]}" | |
| app_dir = (APPS_DIR / app_id).resolve() | |
| app_dir.mkdir(parents=True, exist_ok=True) | |
| files = data.get("files") | |
| if not isinstance(files, list) or not files: | |
| return {"error": "Provide files: [{path, content}, ...]"} | |
| written = [] | |
| for file_item in files: | |
| path = safe_app_file(app_dir, file_item.get("path", "app.py")) | |
| path.parent.mkdir(parents=True, exist_ok=True) | |
| path.write_text(str(file_item.get("content", ""))) | |
| written.append(str(path.relative_to(app_dir.resolve()))) | |
| port = int(data.get("port") or next_app_port()) | |
| start_command = str(data.get("start_command") or data.get("command") or "python3 app.py") | |
| record = { | |
| "app_id": app_id, | |
| "name": name, | |
| "description": str(data.get("description") or ""), | |
| "path": str(app_dir), | |
| "files": written, | |
| "port": port, | |
| "start_command": start_command, | |
| "status": "stopped", | |
| "pid": None, | |
| "stdout": "", | |
| "stderr": "", | |
| "created_at": datetime.now(timezone.utc).isoformat(), | |
| "started_at": None, | |
| "proxy_url": f"/apps/{app_id}/proxy/", | |
| "_popen": None, | |
| } | |
| with app_lock: | |
| apps[app_id] = record | |
| save_apps() | |
| add_memory( | |
| title=f"Generated app: {name}", | |
| content=json.dumps({k: v for k, v in record.items() if k != "_popen"}, indent=2), | |
| source="app-builder", | |
| tags=["generated-app", "vm", "backend"], | |
| metadata={"app_id": app_id, "files": written}, | |
| importance=0.85, | |
| ) | |
| return redact_app(record) | |
| def stop_generated_app(app_id: str) -> dict: | |
| record = apps.get(app_id) | |
| if not record: | |
| return {"error": "App not found"} | |
| popen = record.get("_popen") | |
| if popen and record.get("status") == "running": | |
| try: | |
| if hasattr(os, "killpg"): | |
| os.killpg(os.getpgid(popen.pid), signal.SIGTERM) | |
| else: | |
| popen.terminate() | |
| except Exception as e: | |
| return {"error": str(e)} | |
| record["status"] = "stopped" | |
| record["pid"] = None | |
| record["_popen"] = None | |
| save_apps() | |
| return redact_app(record) | |
| def start_generated_app(app_id: str) -> tuple[dict, int]: | |
| record = apps.get(app_id) | |
| if not record: | |
| return {"error": "App not found"}, 404 | |
| existing = record.get("_popen") | |
| if existing and existing.poll() is None: | |
| record["status"] = "running" | |
| return redact_app(record), 200 | |
| port = int(record["port"]) | |
| proc = subprocess.Popen( | |
| record["start_command"], | |
| shell=True, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.PIPE, | |
| text=True, | |
| cwd=record["path"], | |
| env=runtime_env({"PORT": port, "HOST": "0.0.0.0"}), | |
| preexec_fn=os.setsid if hasattr(os, "setsid") else None, | |
| ) | |
| record.update({ | |
| "_popen": proc, | |
| "pid": proc.pid, | |
| "status": "running", | |
| "started_at": datetime.now(timezone.utc).isoformat(), | |
| "stdout": "", | |
| "stderr": "", | |
| }) | |
| def reader(): | |
| stdout, stderr = proc.communicate() | |
| record["stdout"] += stdout or "" | |
| record["stderr"] += stderr or "" | |
| if record.get("_popen") is proc: | |
| record["status"] = "finished" if proc.returncode == 0 else "failed" | |
| record["pid"] = None | |
| record["_popen"] = None | |
| save_apps() | |
| threading.Thread(target=reader, daemon=True).start() | |
| save_apps() | |
| time.sleep(0.8) | |
| return redact_app(record), 202 | |
| def parse_llm_json(text: str) -> dict: | |
| cleaned = text.strip() | |
| if cleaned.startswith("```"): | |
| cleaned = re.sub(r"^```(?:json)?\s*", "", cleaned) | |
| cleaned = re.sub(r"\s*```$", "", cleaned) | |
| match = re.search(r"\{.*\}", cleaned, re.DOTALL) | |
| if match: | |
| cleaned = match.group(0) | |
| return json.loads(cleaned) | |
| def fallback_app_spec(prompt: str, reason: str = "") -> dict: | |
| marker_match = re.search(r"exact text\s+([A-Za-z0-9_.:-]+)", prompt, re.IGNORECASE) | |
| marker = marker_match.group(1) if marker_match else "llm-generated-vm-app" | |
| safe_prompt = json.dumps(prompt[:3000]) | |
| safe_reason = json.dumps(reason[:1000]) | |
| content = f'''import os | |
| from flask import Flask, jsonify, request | |
| app = Flask(__name__) | |
| PROMPT = {safe_prompt} | |
| BUILD_NOTE = {safe_reason} | |
| @app.route("/") | |
| def home(): | |
| return f"""<!doctype html> | |
| <html><head><title>Generated VM App</title></head> | |
| <body style="margin:0;font-family:system-ui;background:linear-gradient(135deg,#020617,#4c1d95);color:white;min-height:100vh;display:grid;place-items:center"> | |
| <main style="max-width:820px;padding:48px"> | |
| <p style="letter-spacing:.18em;text-transform:uppercase;color:#67e8f9">HF VM Studio fallback backend</p> | |
| <h1>{marker}</h1> | |
| <p>This app was created from your prompt and is running inside the Hugging Face VM.</p> | |
| <form method="post" action="/api/echo"><input name="text" placeholder="send text" style="padding:12px;border:0;border-radius:10px"><button style="padding:12px 16px;border:0;border-radius:10px;margin-left:8px">Echo</button></form> | |
| <p><a style="color:#a7f3d0" href="/api/status">/api/status</a></p> | |
| <pre style="white-space:pre-wrap;background:rgba(255,255,255,.12);padding:16px;border-radius:14px">{{PROMPT}}</pre> | |
| </main></body></html>""" | |
| @app.route("/api/status") | |
| def status(): | |
| return jsonify(ok=True, marker="{marker}", prompt=PROMPT, build_note=BUILD_NOTE, port=os.environ.get("PORT")) | |
| @app.route("/api/echo", methods=["GET", "POST"]) | |
| def echo(): | |
| value = request.values.get("text", "") | |
| return jsonify(ok=True, echo=value) | |
| if __name__ == "__main__": | |
| app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 9000))) | |
| ''' | |
| return { | |
| "name": f"fallback-{slugify(marker)}", | |
| "description": "Runnable Flask backend generated when the LLM returned malformed app JSON.", | |
| "start_command": "python3 app.py", | |
| "files": [{"path": "app.py", "content": content}], | |
| } | |
| def normalize_generated_app_spec(app_spec: dict, prompt: str = "") -> dict: | |
| if not isinstance(app_spec, dict): | |
| return app_spec | |
| files = app_spec.get("files") | |
| if not isinstance(files, list): | |
| return app_spec | |
| for file_item in files: | |
| path = str(file_item.get("path", "")) | |
| content = str(file_item.get("content", "")) | |
| if path.endswith(".py") and "Flask(" in content and "app.run" in content: | |
| lines = content.splitlines() | |
| cleaned = [] | |
| i = 0 | |
| while i < len(lines): | |
| stripped = lines[i].strip() | |
| next_stripped = lines[i + 1].strip() if i + 1 < len(lines) else "" | |
| if stripped.startswith("if __name__") and "app.run" in next_stripped: | |
| i += 2 | |
| continue | |
| if re.match(r"^app\.run\s*\(", stripped): | |
| i += 1 | |
| continue | |
| cleaned.append(lines[i]) | |
| i += 1 | |
| cleaned_text = "\n".join(cleaned).rstrip() | |
| cleaned_text += ( | |
| "\n\nif __name__ == \"__main__\":\n" | |
| " app.run(host=\"0.0.0.0\", port=int(os.environ.get(\"PORT\", 9000)))\n" | |
| ) | |
| if "import os" not in cleaned_text: | |
| cleaned_text = "import os\n" + cleaned_text | |
| prompt_routes = sorted(set(re.findall(r"(/api/[A-Za-z0-9_./-]+)", prompt or ""))) | |
| missing_routes = [route.rstrip(".") for route in prompt_routes if route.rstrip(".") not in cleaned_text] | |
| if missing_routes: | |
| if "jsonify" not in cleaned_text: | |
| if "from flask import Flask" in cleaned_text: | |
| cleaned_text = cleaned_text.replace("from flask import Flask", "from flask import Flask, jsonify", 1) | |
| else: | |
| cleaned_text = "from flask import jsonify\n" + cleaned_text | |
| extra_routes = [] | |
| for route in missing_routes: | |
| func = "generated_" + re.sub(r"[^A-Za-z0-9_]", "_", route.strip("/")) | |
| extra_routes.append( | |
| f'\n@app.route("{route}")\n' | |
| f"def {func}():\n" | |
| f' return jsonify(ok=True, path="{route}")\n' | |
| ) | |
| marker = '\n\nif __name__ == "__main__":' | |
| if marker in cleaned_text: | |
| cleaned_text = cleaned_text.replace(marker, "\n".join(extra_routes) + marker, 1) | |
| else: | |
| cleaned_text += "\n" + "\n".join(extra_routes) | |
| file_item["content"] = cleaned_text | |
| app_spec["start_command"] = "python3 app.py" | |
| if "flask run" in str(app_spec.get("start_command", "")).lower(): | |
| app_spec["start_command"] = "python3 app.py" | |
| return app_spec | |
| def call_llm(prompt: str, system: str = "", **options) -> dict: | |
| llm_cfg = settings.get("llm", {}) | |
| api_base = str(options.get("api_base") or llm_cfg.get("api_base") or "https://api.openai.com/v1").rstrip("/") | |
| model = str(options.get("model") or llm_cfg.get("model") or "gpt-4o-mini") | |
| api_key = ( | |
| options.get("api_key") | |
| or settings.get("env", {}).get("LLM_API_KEY") | |
| or settings.get("env", {}).get("OPENAI_API_KEY") | |
| or settings.get("env", {}).get("OPENROUTER_API_KEY") | |
| or settings.get("env", {}).get("GROQ_API_KEY") | |
| or os.environ.get("LLM_API_KEY") | |
| or os.environ.get("OPENAI_API_KEY") | |
| or os.environ.get("OPENROUTER_API_KEY") | |
| or os.environ.get("GROQ_API_KEY") | |
| ) | |
| if not api_key: | |
| raise ValueError("No LLM API key configured.") | |
| messages = [] | |
| if system: | |
| messages.append({"role": "system", "content": system}) | |
| messages.append({"role": "user", "content": prompt}) | |
| payload = { | |
| "model": model, | |
| "messages": messages, | |
| "temperature": float(options.get("temperature", 0.25)), | |
| "max_tokens": int(options.get("max_tokens", 1800)), | |
| } | |
| if options.get("response_format"): | |
| payload["response_format"] = options["response_format"] | |
| response = requests.post( | |
| f"{api_base}/chat/completions", | |
| headers={"authorization": f"Bearer {api_key}", "content-type": "application/json"}, | |
| json=payload, | |
| timeout=bounded_timeout(options.get("timeout", 90)), | |
| ) | |
| result = response.json() | |
| content = "" | |
| try: | |
| content = result["choices"][0]["message"]["content"] | |
| except Exception: | |
| pass | |
| usage = result.get("usage", {}) | |
| input_tokens = usage.get("prompt_tokens", 0) or usage.get("input_tokens", 0) or len(prompt) // 4 | |
| output_tokens = usage.get("completion_tokens", 0) or usage.get("output_tokens", 0) or len(content) // 4 | |
| proof = generate_inference_proof( | |
| model=model, | |
| prompt=prompt, | |
| response=content, | |
| provider=api_base.split("//")[-1].split(".")[0], | |
| api_base=api_base, | |
| latency_ms=0.0, | |
| input_tokens=input_tokens, | |
| output_tokens=output_tokens, | |
| ) | |
| return {"api_base": api_base, "model": model, "response": content, "raw": result, "proof": proof} | |
| def get_kernel(): | |
| global kernel_manager, kernel_client | |
| with kernel_lock: | |
| if kernel_manager and kernel_client: | |
| return kernel_manager, kernel_client | |
| from jupyter_client import KernelManager | |
| os.environ.update(runtime_env()) | |
| kernel_manager = KernelManager(kernel_name="python3") | |
| kernel_manager.start_kernel(cwd=runtime_cwd()) | |
| kernel_client = kernel_manager.client() | |
| kernel_client.start_channels() | |
| kernel_client.wait_for_ready(timeout=30) | |
| # Inject notebook-exposed helpers into kernel namespace | |
| try: | |
| helper_code = ( | |
| "import json, os, requests, time, textwrap, uuid\n" | |
| "from datetime import datetime, timezone\n" | |
| "from typing import Optional\n" | |
| "\n" | |
| "LLM_ROUTES = {\n" | |
| " 'fast': {'provider': 'groq', 'model': 'llama-3.1-8b-instant', 'api_base': 'https://api.groq.com/openai/v1'},\n" | |
| " 'cheap': {'provider': 'groq', 'model': 'llama-3.1-8b-instant', 'api_base': 'https://api.groq.com/openai/v1'},\n" | |
| " 'quality': {'provider': 'openrouter', 'model': 'openai/gpt-4o', 'api_base': 'https://openrouter.ai/api/v1'},\n" | |
| " 'coding': {'provider': 'groq', 'model': 'llama-3.3-70b-versatile', 'api_base': 'https://api.groq.com/openai/v1'},\n" | |
| " 'json': {'provider': 'groq', 'model': 'llama-3.1-8b-instant', 'api_base': 'https://api.groq.com/openai/v1'},\n" | |
| "}\n" | |
| "\n" | |
| "def _resolve_key(provider):\n" | |
| " env = dict(os.environ)\n" | |
| " if provider == 'groq':\n" | |
| " return env.get('GROQ_API_KEY') or env.get('LLM_API_KEY')\n" | |
| " if provider == 'openrouter':\n" | |
| " return env.get('OPENROUTER_API_KEY') or env.get('LLM_API_KEY')\n" | |
| " return env.get('LLM_API_KEY')\n" | |
| "\n" | |
| "def llm_infer(mode='cheap', task='', messages=None, system='', temperature=0.25, max_tokens=1800, timeout=90):\n" | |
| " messages = messages or []\n" | |
| " if not messages and task:\n" | |
| " messages = [{'role': 'user', 'content': task}]\n" | |
| " if not messages:\n" | |
| " raise ValueError('Provide messages or task')\n" | |
| " route = LLM_ROUTES.get(mode, LLM_ROUTES['cheap'])\n" | |
| " provider = route['provider']\n" | |
| " model = route['model']\n" | |
| " api_base = route['api_base']\n" | |
| " api_key = _resolve_key(provider)\n" | |
| " if not api_key:\n" | |
| " raise ValueError(f'No API key for {provider}')\n" | |
| " prompt = messages[-1].get('content', '') if messages else ''\n" | |
| " if mode == 'json':\n" | |
| " system = (system or '') + '\\nReturn only valid JSON. No markdown fences.'\n" | |
| " if mode == 'coding':\n" | |
| " system = (system or '') + '\\nYou are an expert programmer. Write clean, production-ready code.'\n" | |
| " payload = {'model': model, 'messages': [{'role': 'system', 'content': system}] + messages if system else messages, 'temperature': temperature, 'max_tokens': max_tokens}\n" | |
| " if mode == 'json':\n" | |
| " payload['response_format'] = {'type': 'json_object'}\n" | |
| " started = time.time()\n" | |
| " r = requests.post(f'{api_base}/chat/completions', headers={'authorization': f'Bearer {api_key}', 'content-type': 'application/json'}, json=payload, timeout=timeout)\n" | |
| " latency_ms = round((time.time() - started) * 1000, 2)\n" | |
| " result = r.json()\n" | |
| " answer = result.get('choices', [{}])[0].get('message', {}).get('content', '')\n" | |
| " usage = result.get('usage', {})\n" | |
| " inp = usage.get('prompt_tokens', 0) or len(prompt)//4\n" | |
| " out = usage.get('completion_tokens', 0) or len(answer)//4\n" | |
| " cost = round((inp + out) / 1000 * {'llama-3.1-8b-instant': 0.00005, 'llama-3.3-70b-versatile': 0.00059, 'openai/gpt-4o': 0.005}.get(model, 0.0001), 6)\n" | |
| " return {'answer': answer, 'provider': provider, 'model': model, 'latency_ms': latency_ms, 'cost_usd': cost, 'input_tokens': inp, 'output_tokens': out, 'route_reason': f'mode={mode} -> {provider} -> {model}', 'raw': result}\n" | |
| ) | |
| kernel_client.execute(helper_code, silent=True, user_expressions={}) | |
| except Exception: | |
| logger.warning("Failed to inject helpers into kernel namespace") | |
| try: | |
| kernel_client.execute("globals()['llm_infer'] = llm_infer\n", silent=True, user_expressions={}) | |
| except Exception: | |
| pass | |
| return kernel_manager, kernel_client | |
| def shutdown_kernel(): | |
| global kernel_manager, kernel_client | |
| with kernel_lock: | |
| if kernel_client: | |
| try: | |
| kernel_client.stop_channels() | |
| except Exception: | |
| pass | |
| if kernel_manager: | |
| try: | |
| kernel_manager.shutdown_kernel(now=True) | |
| except Exception: | |
| pass | |
| kernel_manager = None | |
| kernel_client = None | |
| def execute_kernel_code(code: str, timeout: int = 60) -> dict: | |
| timeout = bounded_timeout(timeout) | |
| with kernel_lock: | |
| _, client = get_kernel() | |
| msg_id = client.execute(code, allow_stdin=False) | |
| stdout_chunks = [] | |
| stderr_chunks = [] | |
| display_data = [] | |
| error = None | |
| started = time.time() | |
| while True: | |
| if time.time() - started > timeout: | |
| try: | |
| kernel_manager.interrupt_kernel() | |
| except Exception: | |
| pass | |
| return { | |
| "success": False, | |
| "execution_state": "timeout", | |
| "stdout": "".join(stdout_chunks), | |
| "stderr": "".join(stderr_chunks) + "\nKernel execution timed out", | |
| "display_data": display_data, | |
| "error": "timeout", | |
| } | |
| msg = client.get_iopub_msg(timeout=1) | |
| if msg.get("parent_header", {}).get("msg_id") != msg_id: | |
| continue | |
| msg_type = msg["header"]["msg_type"] | |
| content = msg.get("content", {}) | |
| if msg_type == "stream": | |
| if content.get("name") == "stderr": | |
| stderr_chunks.append(content.get("text", "")) | |
| else: | |
| stdout_chunks.append(content.get("text", "")) | |
| elif msg_type in {"display_data", "execute_result"}: | |
| display_data.append(content.get("data", {})) | |
| elif msg_type == "error": | |
| error = { | |
| "ename": content.get("ename"), | |
| "evalue": content.get("evalue"), | |
| "traceback": content.get("traceback", []), | |
| } | |
| stderr_chunks.append("\n".join(error["traceback"])) | |
| elif msg_type == "status" and content.get("execution_state") == "idle": | |
| break | |
| return { | |
| "success": error is None, | |
| "execution_state": "idle", | |
| "stdout": "".join(stdout_chunks), | |
| "stderr": "".join(stderr_chunks), | |
| "display_data": display_data, | |
| "error": error, | |
| } | |
| # ββ Flask App βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| app = Flask(__name__) | |
| def index(): | |
| html = """<!DOCTYPE html> | |
| <html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"> | |
| <title>HF VM Studio</title> | |
| <style> | |
| :root{--bg:#070814;--ink:#f8fbff;--muted:#a9b2c7;--line:rgba(255,255,255,.14);--hot:#7c3aed;--cyan:#22d3ee;--lime:#a3e635} | |
| *{box-sizing:border-box}body{margin:0;background:radial-gradient(circle at 12% 8%,rgba(124,58,237,.42),transparent 34%),radial-gradient(circle at 86% 0,rgba(34,211,238,.34),transparent 30%),linear-gradient(145deg,#060712,#0b1022 48%,#101827);color:var(--ink);font:15px Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,sans-serif;min-height:100vh;overflow-x:hidden} | |
| .mesh{position:fixed;inset:0;background-image:linear-gradient(var(--line) 1px,transparent 1px),linear-gradient(90deg,var(--line) 1px,transparent 1px);background-size:44px 44px;mask-image:radial-gradient(circle at center,black,transparent 72%);opacity:.32;pointer-events:none}.orb{position:fixed;width:520px;height:520px;border-radius:50%;filter:blur(55px);background:conic-gradient(from 90deg,var(--hot),var(--cyan),var(--lime),var(--hot));opacity:.13;right:-120px;bottom:-150px} | |
| header{display:flex;align-items:center;justify-content:space-between;padding:28px min(7vw,92px);position:relative;z-index:2}.brand{display:flex;align-items:center;gap:12px;font-weight:800;letter-spacing:-.03em}.mark{width:40px;height:40px;border-radius:14px;background:linear-gradient(135deg,var(--cyan),var(--hot));display:grid;place-items:center;box-shadow:0 0 42px rgba(34,211,238,.45)}nav{display:flex;gap:12px;flex-wrap:wrap}nav a{color:var(--muted);text-decoration:none;border:1px solid var(--line);padding:10px 14px;border-radius:999px;background:rgba(255,255,255,.04);backdrop-filter:blur(12px)} | |
| .hero{position:relative;z-index:1;padding:64px min(7vw,92px) 48px;display:grid;grid-template-columns:minmax(0,1.05fr) minmax(320px,.95fr);gap:48px;align-items:center}.eyebrow{display:inline-flex;gap:9px;align-items:center;padding:9px 13px;border:1px solid var(--line);border-radius:999px;background:rgba(255,255,255,.06);color:#dbeafe}.pulse{width:8px;height:8px;border-radius:99px;background:var(--lime);box-shadow:0 0 18px var(--lime)}h1{font-size:clamp(48px,8vw,100px);line-height:.9;letter-spacing:-.08em;margin:22px 0 20px}.grad{background:linear-gradient(100deg,#fff,#c4b5fd 38%,#67e8f9 72%,#ecfccb);-webkit-background-clip:text;background-clip:text;color:transparent}.lead{max-width:720px;color:var(--muted);font-size:clamp(18px,2vw,23px);line-height:1.55}.launch{display:flex;gap:10px;margin-top:28px;flex-wrap:wrap}.launch input{min-width:300px;flex:1;border:1px solid var(--line);border-radius:16px;background:rgba(255,255,255,.08);color:white;padding:15px 16px;font:14px ui-monospace,Menlo,monospace;outline:0}.launch button,.primary{border:0;border-radius:16px;background:linear-gradient(135deg,var(--cyan),var(--hot));color:white;padding:15px 20px;font-weight:800;cursor:pointer;box-shadow:0 18px 60px rgba(124,58,237,.32)}.stack{display:grid;gap:16px}.panel{border:1px solid var(--line);border-radius:28px;background:linear-gradient(180deg,rgba(255,255,255,.12),rgba(255,255,255,.05));box-shadow:0 30px 90px rgba(0,0,0,.36);backdrop-filter:blur(18px);padding:20px}.term{font:13px/1.7 ui-monospace,Menlo,monospace;color:#d1fae5}.term b{color:#67e8f9}.status{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}.stat{border:1px solid var(--line);border-radius:20px;padding:16px;background:rgba(255,255,255,.05)}.stat strong{display:block;font-size:24px}.features{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px;padding:18px min(7vw,92px) 70px}.feature{border:1px solid var(--line);border-radius:24px;background:rgba(255,255,255,.06);padding:20px;min-height:150px}.feature h3{margin:0 0 9px}.feature p{color:var(--muted);line-height:1.5;margin:0}@media(max-width:920px){.hero{grid-template-columns:1fr}.features{grid-template-columns:1fr 1fr}}@media(max-width:620px){header{align-items:flex-start;gap:16px;flex-direction:column}.features{grid-template-columns:1fr}.launch input{min-width:100%}} | |
| </style></head><body><div class="mesh"></div><div class="orb"></div> | |
| <header><div class="brand"><div class="mark">VM</div><span>HF VM Studio</span></div><nav><a href="/api">API map</a><a href="/healthz">Health</a><a href="/status">Status</a></nav></header> | |
| <main class="hero"><section><div class="eyebrow"><span class="pulse"></span>Agent-native cloud workbench on a cheap Hugging Face Space</div><h1>Prompt to backend. <span class="grad">Running, remembered, deployable.</span></h1><p class="lead">HF VM Studio turns a Hugging Face Space into a prompt-to-backend factory, memory vault, notebook runtime, and deployment bridge. The primitive is simple: prompt -> files -> process -> proxy URL -> memory receipt -> deploy action.</p><div class="launch"><input id="token" type="password" placeholder="Paste terminal access token"><button onclick="openWorkbench()">Enter Workbench</button></div></section> | |
| <section class="stack"><div class="panel term"><b>$</b> python3 app.py<br><b>β</b> persistent Jupyter kernel<br><b>β</b> shell cells and background processes<br><b>β</b> /apps/<id>/proxy live endpoint<br><b>β</b> memory saved from every meaningful run</div><div class="status"><div class="stat"><strong id="apps">--</strong>apps</div><div class="stat"><strong id="mem">--</strong>memories</div><div class="stat"><strong id="procs">--</strong>processes</div></div></section></main> | |
| <section class="features"><div class="feature"><h3>VM Workbench</h3><p>Shell, Python cells, background processes, logs, previews, and deploy controls from one protected browser surface.</p></div><div class="feature"><h3>Agent Builder</h3><p>Prompt a backend, write files to disk, start it on an internal port, then preview it through the Space proxy.</p></div><div class="feature"><h3>Execution Memory</h3><p>Commands, notebooks, LLM output, generated apps, and deployments become searchable memory.</p></div><div class="feature"><h3>Proof Receipts</h3><p>Every important action gets prompt hashes, file hashes, command metadata, app URLs, model info, and timestamps.</p></div></section> | |
| <script> | |
| function openWorkbench(){const t=document.getElementById('token').value.trim();if(!t){alert('Paste the terminal access token first.');return}location.href='/colab?token='+encodeURIComponent(t)} | |
| fetch('/status').then(r=>r.json()).then(j=>{apps.textContent=j.apps||0;mem.textContent=j.memories||0;procs.textContent=j.background_processes||0}).catch(()=>{}) | |
| </script></body></html>""" | |
| return Response(html, mimetype="text/html") | |
| def api_index(): | |
| return jsonify({ | |
| "status": "running", | |
| "message": "HF VM Studio", | |
| "auth_required": True, | |
| "endpoints": { | |
| "GET /status": "Agent status & uptime", | |
| "GET /logs": "Recent logs", | |
| "GET /settings": "Runtime settings with secrets redacted", | |
| "POST /settings": "Update cwd, env, LLM, and deploy settings", | |
| "GET /memory": "List saved memories", | |
| "POST /memory": "Save a memory", | |
| "POST /memory/search": "Search saved memories", | |
| "GET /receipts": "List provenance receipts", | |
| "POST /receipts/search": "Search provenance receipts", | |
| "GET /receipts/<receipt_id>": "Inspect one receipt", | |
| "GET /tasks": "List tasks", | |
| "POST /execute": "Execute command", | |
| "POST /execute/background": "Launch a background shell command", | |
| "GET /processes": "List background processes", | |
| "POST /kernel/execute": "Execute code in a persistent Jupyter kernel", | |
| "POST /kernel/restart": "Restart the Jupyter kernel", | |
| "POST /notebook/run": "Run a multi-cell notebook through the kernel", | |
| "POST /llm": "Run an OpenAI-compatible LLM request", | |
| "POST /api/v1/llm/infer": "Inference mesh β mode-based routed LLM with cost/latency/receipt", | |
| "GET /apps": "List generated backend apps", | |
| "POST /apps": "Create a generated backend app from files", | |
| "POST /agent/build": "Ask the configured LLM to generate a backend app", | |
| "POST /apps/<app_id>/start": "Start a generated backend app", | |
| "POST /apps/<app_id>/stop": "Stop a generated backend app", | |
| "GET /apps/<app_id>/proxy/...": "Proxy to the running backend app", | |
| "GET /stripe/config": "Stripe publishable key + app origin (public)", | |
| "POST /stripe/checkout": "Create a Stripe Checkout session", | |
| "POST /stripe/webhook": "Stripe webhook handler", | |
| "GET /wallet/nonce": "Get challenge nonce for wallet signature", | |
| "POST /wallet/connect": "Connect MetaMask or Phantom wallet", | |
| "GET /wallet/<address>": "Get wallet balance and info", | |
| "GET /wallet/<address>/history": "Token transaction history", | |
| "GET /tokens/leaderboard": "Token balance leaderboard", | |
| "POST /tokens/buy": "Buy token packs via Stripe", | |
| "POST /tokens/launch": "Launch an SPL token on Solana (costs tokens)", | |
| "GET /tokens/launched": "List tokens launched by a wallet", | |
| "POST /claimos/evaluate": "Create/evaluate a claim: evidence + probability state + receipt", | |
| "GET /claimos/<claim_id>": "Get full claim state with evidence and contradictions", | |
| "POST /claimos/<claim_id>/contradictions": "Run contradiction scan on a claim", | |
| "GET /claimos/<claim_id>/greeks": "Compute Claim Greeks (Ξ, Ξ, Ξ, V, K)", | |
| "GET /claimos/<claim_id>/liquidity": "Compute finance readiness / liquidity score", | |
| "POST /claimos/<claim_id>/assess": "LLM-powered evidence quality assessment (auto-rates strength)", | |
| "GET /claimos/<claim_id>/appraise": "Full legal appraisal report via LLM", | |
| "GET /tokens/verify/<mint_address>": "On-chain Solana token mint verification via RPC", | |
| "POST /pixelator/ingest": "Ingest HTML β glyph units (costs tokens)", | |
| "GET /pixelator/page/<page_id>/glyphs": "Get glyph units for a page", | |
| "GET /pixelator/page/<page_id>/activation": "Page activation summary with glyph stats", | |
| "GET /pixelator/website/<website_id>/top-glyphs": "Highest-value glyphs across a website", | |
| "POST /pixelator/learn": "Retrain DOM weights and lexicon from actual page results", | |
| "GET /costs": "Get all token costs (DB-backed, no hardcoded values)", | |
| "POST /costs": "Update a token cost (admin)", | |
| "GET /crawler/targets": "List crawl target websites (GA-RL population)", | |
| "POST /crawler/targets": "Register a new crawl target website", | |
| "POST /crawler/queue": "Enqueue URL into rotator buffer", | |
| "GET /crawler/queue": "List crawl queue", | |
| "POST /crawler/ingest": "Run one RL crawl step: fetch + pixelate + reward", | |
| "GET /crawler/results": "Crawl results with glyph metrics", | |
| "POST /crawler/evolve": "Run one GA generation on target population", | |
| "GET /crawler/policy": "Get RL Q-table policy state", | |
| "GET /finance/collateral": "Underwriting proof: revenue, deferred revenue, token velocity", | |
| "GET /finance/revenue": "Revenue ledger with period/source breakdown", | |
| "POST /finance/reconcile": "Reconcile Stripe sessions with token credits", | |
| "POST /finance/rollback": "Rollback a transaction by tx_id", | |
| "POST /deploy/vercel": "Deploy a project directory with Vercel CLI", | |
| "POST /deploy/netlify": "Deploy a project directory with Netlify CLI", | |
| "GET /terminal": "Web terminal UI", | |
| }, | |
| }) | |
| def get_status(): | |
| return jsonify({ | |
| "running": True, | |
| "start_time": state.get("start_time"), | |
| "uptime": get_uptime(), | |
| "scheduled_tasks": len(schedule.jobs), | |
| "executed_tasks_count": len(state.get("executed_tasks", [])), | |
| "background_processes": len(processes), | |
| "apps": len(apps), | |
| "receipts": len(receipts), | |
| "memories": len([m for m in memories.values() if not m.get("tombstone_at")]), | |
| "kernel_running": kernel_manager is not None, | |
| "cwd": str(DEFAULT_CWD), | |
| "runtime_cwd": runtime_cwd(), | |
| "token_rewards": {k: v for k, v in TOKEN_REWARDS.items()}, | |
| "settings": redacted_settings(), | |
| }) | |
| def healthz(): | |
| return jsonify({"ok": True, "status": "healthy", "uptime": get_uptime()}) | |
| def get_settings(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| return jsonify(redacted_settings()) | |
| def update_settings(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| data = request.json or {} | |
| with settings_lock: | |
| if "cwd" in data: | |
| settings["cwd"] = str(data["cwd"]) | |
| if "max_timeout" in data: | |
| settings["max_timeout"] = int(data["max_timeout"]) | |
| if isinstance(data.get("env"), dict): | |
| for key, value in data["env"].items(): | |
| key = str(key).strip() | |
| if not key: | |
| continue | |
| if value is None or value == "": | |
| settings["env"].pop(key, None) | |
| else: | |
| settings["env"][key] = str(value) | |
| if isinstance(data.get("llm"), dict): | |
| settings["llm"].update({k: str(v) for k, v in data["llm"].items() if v is not None}) | |
| if isinstance(data.get("deploy"), dict): | |
| settings["deploy"].update({k: str(v) for k, v in data["deploy"].items() if v is not None}) | |
| save_settings() | |
| os.environ.update(runtime_env()) | |
| try: | |
| shutdown_kernel() | |
| except Exception: | |
| logger.exception("Failed to reset kernel after settings update") | |
| add_memory( | |
| title="Runtime settings updated", | |
| content=json.dumps(redacted_settings(), indent=2), | |
| source="settings", | |
| tags=["settings", "runtime"], | |
| metadata={"keys": list(data.keys())}, | |
| importance=0.65, | |
| ) | |
| return jsonify(redacted_settings()) | |
| def get_logs(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if log_file.exists(): | |
| lines = log_file.read_text().splitlines() | |
| return jsonify({"logs": lines[-100:]}) | |
| return jsonify({"logs": [], "message": "No logs yet"}) | |
| def list_tasks(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| return jsonify({"tasks": tasks}) | |
| def execute(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"exec:{request.remote_addr}", window=60, max_requests=20): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| cmd = _clamp_str(data.get("command", ""), max_len=8000).strip() | |
| timeout = bounded_timeout(data.get("timeout", 60)) | |
| cwd = data.get("cwd") | |
| if not cmd: | |
| return jsonify({"error": "Missing command"}), 400 | |
| result = run_command(cmd, timeout, cwd=cwd) | |
| add_memory( | |
| title=f"Terminal command: {cmd[:80]}", | |
| content=f"command: {cmd}\nstdout:\n{result.get('stdout','')}\nstderr:\n{result.get('stderr','')}", | |
| source="terminal", | |
| tags=["terminal", "command"], | |
| metadata={"exit_code": result.get("exit_code"), "success": result.get("success"), "cwd": result.get("cwd")}, | |
| importance=0.6 if result.get("success") else 0.75, | |
| ) | |
| state["executed_tasks"].append({ | |
| "command": cmd, | |
| "timestamp": datetime.now(timezone.utc).isoformat(), | |
| "success": result["success"], | |
| }) | |
| state["executed_tasks"] = state["executed_tasks"][-1000:] | |
| save_state() | |
| receipt = create_receipt( | |
| kind="command", | |
| title=f"Shell command: {cmd[:80]}", | |
| status="success" if result.get("success") else "failed", | |
| command=cmd, | |
| metadata={"result": result}, | |
| ) | |
| result["receipt_id"] = receipt["receipt_id"] | |
| result["token_reward"] = maybe_credit(data, "shell_execute", TOKEN_REWARDS["shell_execute"]) | |
| return jsonify(result) | |
| def list_memory(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| limit = max(1, min(int(request.args.get("limit", 50)), 200)) | |
| active = [m for m in memories.values() if not m.get("tombstone_at")] | |
| active.sort(key=lambda item: item.get("created_at", ""), reverse=True) | |
| return jsonify({"memories": active[:limit], "count": len(active)}) | |
| def create_memory(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| data = request.json or {} | |
| content = _clamp_str(data.get("content", ""), max_len=50000).strip() | |
| if not content: | |
| return jsonify({"error": "Missing content"}), 400 | |
| item = add_memory( | |
| title=_clamp_str(data.get("title") or "Manual memory", 256), | |
| content=content, | |
| source=_clamp_str(data.get("source") or "manual", 64), | |
| tags=data.get("tags") if isinstance(data.get("tags"), list) else ["manual"], | |
| metadata=data.get("metadata") if isinstance(data.get("metadata"), dict) else {}, | |
| importance=float(data.get("importance", 0.7)), | |
| ) | |
| return jsonify(item), 201 | |
| def memory_search(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| data = request.json or {} | |
| query = _clamp_str(data.get("query", ""), max_len=2000).strip() | |
| limit = max(1, min(int(data.get("limit", 8)), 50)) | |
| return jsonify({"query": query, "memories": search_memory(query, limit=limit)}) | |
| def get_memory(memory_id): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| item = memories.get(memory_id) | |
| if not item: | |
| return jsonify({"error": "Memory not found"}), 404 | |
| return jsonify(item) | |
| def delete_memory(memory_id): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| item = memories.get(memory_id) | |
| if not item or item.get("tombstone_at"): | |
| return jsonify({"error": "Active memory not found"}), 404 | |
| item["tombstone_at"] = datetime.now(timezone.utc).isoformat() | |
| save_memory() | |
| return jsonify({"memory_id": memory_id, "status": "tombstoned"}) | |
| def list_receipts(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| limit = max(1, min(int(request.args.get("limit", 50)), 200)) | |
| with receipt_lock: | |
| active = list(receipts.values()) | |
| active.sort(key=lambda item: item.get("created_at", ""), reverse=True) | |
| return jsonify({"receipts": active[:limit], "count": len(active)}) | |
| def receipt_search(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| data = request.json or {} | |
| query = _clamp_str(data.get("query", ""), max_len=2000).strip() | |
| limit = max(1, min(int(data.get("limit", 20)), 100)) | |
| return jsonify({"query": query, "receipts": search_receipts(query, limit=limit)}) | |
| def get_receipt(receipt_id): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| item = receipts.get(receipt_id) | |
| if not item: | |
| return jsonify({"error": "Receipt not found"}), 404 | |
| return jsonify(item) | |
| def run_llm(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"llm:{request.remote_addr}", window=60, max_requests=30): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| prompt = _clamp_str(data.get("prompt", ""), max_len=20000).strip() | |
| if not prompt: | |
| return jsonify({"error": "Missing prompt"}), 400 | |
| try: | |
| result = call_llm( | |
| prompt, | |
| system=str(data.get("system") or ""), | |
| api_base=data.get("api_base"), | |
| model=data.get("model"), | |
| api_key=data.get("api_key"), | |
| temperature=data.get("temperature", 0.3), | |
| max_tokens=data.get("max_tokens", 800), | |
| timeout=data.get("timeout", 60), | |
| ) | |
| except ValueError as e: | |
| return jsonify({"error": str(e)}), 400 | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 502 | |
| add_memory( | |
| title=f"LLM run: {result['model']}", | |
| content=f"prompt:\n{prompt}\n\nresponse:\n{result.get('response') or json.dumps(result.get('raw', {}))[:4000]}", | |
| source="llm", | |
| tags=["llm", result["model"]], | |
| metadata={"api_base": result["api_base"], "model": result["model"]}, | |
| importance=0.8, | |
| ) | |
| receipt = create_receipt( | |
| kind="llm", | |
| title=f"LLM run: {result['model']}", | |
| status="completed", | |
| prompt=prompt, | |
| model={"api_base": result["api_base"], "model": result["model"]}, | |
| metadata={"response_hash": sha256_text(result.get("response") or json.dumps(result.get("raw", {})))}, | |
| ) | |
| result["receipt_id"] = receipt["receipt_id"] | |
| return jsonify(result) | |
| # ββ Inference Mesh ββββββββββββββββββββββββββββββββββββββββββββββ | |
| LLM_ROUTES = { | |
| "fast": {"provider": "groq", "model": "llama-3.1-8b-instant", "api_base": "https://api.groq.com/openai/v1"}, | |
| "cheap": {"provider": "groq", "model": "llama-3.1-8b-instant", "api_base": "https://api.groq.com/openai/v1"}, | |
| "quality": {"provider": "openrouter", "model": "openai/gpt-4o", "api_base": "https://openrouter.ai/api/v1"}, | |
| "local": {"provider": "ollama", "model": "llama3.1:8b", "api_base": "http://localhost:11434/v1"}, | |
| "coding": {"provider": "groq", "model": "llama-3.3-70b-versatile", "api_base": "https://api.groq.com/openai/v1"}, | |
| "json": {"provider": "groq", "model": "llama-3.1-8b-instant", "api_base": "https://api.groq.com/openai/v1"}, | |
| "private": {"provider": "ollama", "model": "llama3.1:8b", "api_base": "http://localhost:11434/v1"}, | |
| } | |
| COST_PER_1K_TOKENS: Dict[str, float] = { | |
| "llama-3.1-8b-instant": 0.00005, | |
| "llama-3.3-70b-versatile": 0.00059, | |
| "openai/gpt-4o": 0.005, | |
| "openai/gpt-4o-mini": 0.00015, | |
| "llama3.1:8b": 0.0, | |
| } | |
| def resolve_api_key(provider: str) -> Optional[str]: | |
| env = settings.get("env", {}) | |
| if provider == "groq": | |
| return env.get("GROQ_API_KEY") or env.get("LLM_API_KEY") or os.environ.get("GROQ_API_KEY") or os.environ.get("LLM_API_KEY") | |
| if provider == "openrouter": | |
| return env.get("OPENROUTER_API_KEY") or env.get("LLM_API_KEY") or os.environ.get("OPENROUTER_API_KEY") or os.environ.get("LLM_API_KEY") | |
| if provider == "ollama": | |
| return "ollama" # Ollama doesn't need a key | |
| return env.get("LLM_API_KEY") or os.environ.get("LLM_API_KEY") | |
| def estimate_cost(model: str, input_tokens: int, output_tokens: int) -> float: | |
| rate = COST_PER_1K_TOKENS.get(model, 0.0001) | |
| return round((input_tokens + output_tokens) / 1000 * rate, 6) | |
| def route_llm_infer(data: dict) -> dict: | |
| mode = str(data.get("mode", "cheap")).strip().lower() | |
| task = _clamp_str(data.get("task", ""), max_len=20000).strip() | |
| messages = data.get("messages", []) | |
| if messages: | |
| messages = [ | |
| {"role": _clamp_str(m.get("role", "user"), 20), "content": _clamp_str(m.get("content", ""), 20000)} | |
| for m in messages | |
| ] | |
| if not messages and task: | |
| messages = [{"role": "user", "content": task}] | |
| if not messages: | |
| raise ValueError("Provide messages or task") | |
| route = LLM_ROUTES.get(mode) | |
| if not route: | |
| route = LLM_ROUTES["cheap"] | |
| provider = route["provider"] | |
| model = str(data.get("model") or route["model"]) | |
| api_base = str(data.get("api_base") or route["api_base"]) | |
| api_key = resolve_api_key(provider) | |
| if provider != "ollama" and not api_key: | |
| # Fallback chain: groq -> openrouter -> error | |
| fallback_order = ["groq", "openrouter"] | |
| for fb in fallback_order: | |
| if fb == provider: | |
| continue | |
| fb_key = resolve_api_key(fb) | |
| if fb_key: | |
| provider = fb | |
| model = LLM_ROUTES[fb]["model"] | |
| api_base = LLM_ROUTES[fb]["api_base"] | |
| api_key = fb_key | |
| break | |
| if not api_key: | |
| raise ValueError(f"No API key available for provider {provider}") | |
| system = str(data.get("system") or "") | |
| if mode == "json": | |
| system = system + "\nReturn only valid JSON. No markdown fences." if system else "Return only valid JSON. No markdown fences." | |
| if mode == "coding": | |
| system = system + "\nYou are an expert programmer. Write clean, production-ready code." if system else "You are an expert programmer. Write clean, production-ready code." | |
| prompt = "" | |
| if messages and isinstance(messages, list) and messages[-1].get("role") == "user": | |
| prompt = str(messages[-1].get("content", "")) | |
| started = time.time() | |
| llm_result = call_llm( | |
| prompt, | |
| system=system, | |
| api_base=api_base, | |
| model=model, | |
| api_key=api_key, | |
| temperature=float(data.get("temperature", 0.25)), | |
| max_tokens=int(data.get("max_tokens", 1800)), | |
| timeout=data.get("timeout", 90), | |
| response_format={"type": "json_object"} if mode == "json" else None, | |
| ) | |
| latency_ms = round((time.time() - started) * 1000, 2) | |
| raw = llm_result.get("raw", {}) | |
| usage = raw.get("usage", {}) | |
| input_tokens = usage.get("prompt_tokens", 0) or usage.get("input_tokens", 0) or len(prompt) // 4 | |
| output_tokens = usage.get("completion_tokens", 0) or usage.get("output_tokens", 0) or len(str(llm_result.get("response", ""))) // 4 | |
| cost_usd = estimate_cost(model, input_tokens, output_tokens) | |
| add_memory( | |
| title=f"Inference mesh [{mode}]: {model}", | |
| content=f"task: {task}\nprompt: {prompt[:500]}\nresponse: {str(llm_result.get('response', ''))[:2000]}", | |
| source="inference-mesh", | |
| tags=["llm", provider, model, mode], | |
| metadata={"provider": provider, "model": model, "mode": mode, "latency_ms": latency_ms, "cost_usd": cost_usd}, | |
| importance=0.85, | |
| ) | |
| # Generate Proof of Inference for every mesh call | |
| proof = generate_inference_proof( | |
| model=model, | |
| prompt=prompt, | |
| response=str(llm_result.get("response", "")), | |
| provider=provider, | |
| api_base=api_base, | |
| latency_ms=latency_ms, | |
| input_tokens=input_tokens, | |
| output_tokens=output_tokens, | |
| ) | |
| receipt = create_receipt( | |
| kind="inference-mesh", | |
| title=f"Inference mesh [{mode}]: {model}", | |
| status="completed", | |
| prompt=prompt, | |
| model={"provider": provider, "model": model, "api_base": api_base, "mode": mode}, | |
| metadata={ | |
| "latency_ms": latency_ms, | |
| "cost_usd": cost_usd, | |
| "input_tokens": input_tokens, | |
| "output_tokens": output_tokens, | |
| "route_reason": f"mode={mode} -> provider={provider} -> model={model}", | |
| "proof_id": proof["proof_id"], | |
| }, | |
| ) | |
| return { | |
| "answer": llm_result.get("response", ""), | |
| "provider": provider, | |
| "model": model, | |
| "latency_ms": latency_ms, | |
| "cost_usd": cost_usd, | |
| "receipt_hash": receipt["receipt_id"], | |
| "proof": proof, | |
| "route_reason": f"mode={mode} -> provider={provider} -> model={model}", | |
| "input_tokens": input_tokens, | |
| "output_tokens": output_tokens, | |
| "api_base": api_base, | |
| "raw": raw, | |
| } | |
| # Notebook-exposed helper (injected into kernel globals) | |
| def llm_infer(mode: str = "cheap", task: str = "", messages: Optional[list] = None, **kwargs) -> dict: | |
| """Cell-friendly inference mesh call. Returns answer + metadata.""" | |
| payload = {"mode": mode, "task": task, "messages": messages or [], **kwargs} | |
| return route_llm_infer(payload) | |
| def api_llm_infer(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"llm:{request.remote_addr}", window=60, max_requests=30): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| try: | |
| result = route_llm_infer(data) | |
| except ValueError as e: | |
| return jsonify({"error": str(e)}), 400 | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 502 | |
| return jsonify(result) | |
| def list_apps(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| return jsonify({"apps": [redact_app(item) for item in apps.values()]}) | |
| def create_app(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| result = create_generated_app(request.json or {}) | |
| if result.get("error"): | |
| return jsonify(result), 400 | |
| receipt = create_receipt( | |
| kind="generated-app", | |
| title=f"Generated app: {result['name']}", | |
| status=result.get("status", "created"), | |
| prompt=str((request.json or {}).get("prompt") or ""), | |
| app_record=result, | |
| command=result.get("start_command", ""), | |
| metadata={"source": "manual-app-create"}, | |
| ) | |
| result["receipt_id"] = receipt["receipt_id"] | |
| attach_receipt_to_app(result["app_id"], receipt["receipt_id"]) | |
| return jsonify(result), 201 | |
| def get_app(app_id): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| item = apps.get(app_id) | |
| if not item: | |
| return jsonify({"error": "App not found"}), 404 | |
| return jsonify(redact_app(item)) | |
| def get_app_files(app_id): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| item = apps.get(app_id) | |
| if not item: | |
| return jsonify({"error": "App not found"}), 404 | |
| app_dir = Path(item["path"]) | |
| files = [] | |
| for file_name in item.get("files", []): | |
| file_path = safe_app_file(app_dir, file_name) | |
| files.append({"path": file_name, "content": file_path.read_text() if file_path.exists() else ""}) | |
| return jsonify({"app_id": app_id, "files": files}) | |
| def start_app(app_id): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| result, status = start_generated_app(app_id) | |
| if not result.get("error"): | |
| receipt = create_receipt( | |
| kind="app-start", | |
| title=f"App started: {result.get('name', app_id)}", | |
| status=result.get("status", "running"), | |
| app_record=result, | |
| command=result.get("start_command", ""), | |
| process={"pid": result.get("pid"), "status": result.get("status"), "stdout": result.get("stdout", ""), "stderr": result.get("stderr", "")}, | |
| metadata={"app_id": app_id, "proxy_url": result.get("proxy_url")}, | |
| ) | |
| result["start_receipt_id"] = receipt["receipt_id"] | |
| return jsonify(result), status | |
| def stop_app(app_id): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| result = stop_generated_app(app_id) | |
| if result.get("error"): | |
| return jsonify(result), 404 | |
| return jsonify(result) | |
| def proxy_app(app_id, subpath): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| item = apps.get(app_id) | |
| if not item: | |
| return jsonify({"error": "App not found"}), 404 | |
| target = f"http://127.0.0.1:{int(item['port'])}/{subpath}" | |
| try: | |
| upstream = requests.request( | |
| request.method, | |
| target, | |
| params=request.args, | |
| data=request.get_data(), | |
| headers={k: v for k, v in request.headers if k.lower() not in {"host", "content-length"}}, | |
| timeout=30, | |
| allow_redirects=False, | |
| ) | |
| except Exception as e: | |
| return Response(f"App proxy error: {e}", status=502, mimetype="text/plain") | |
| excluded = {"content-encoding", "content-length", "transfer-encoding", "connection"} | |
| headers = [(k, v) for k, v in upstream.headers.items() if k.lower() not in excluded] | |
| return Response(upstream.content, status=upstream.status_code, headers=headers) | |
| def agent_build_app(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"build:{request.remote_addr}", window=60, max_requests=10): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| prompt = _clamp_str(data.get("prompt", ""), max_len=12000).strip() | |
| if not prompt: | |
| return jsonify({"error": "Missing prompt"}), 400 | |
| system = ( | |
| "You are an expert backend app generator for a Hugging Face Spaces Linux VM. " | |
| "Return only valid JSON with keys: name, description, start_command, files. " | |
| "files must be an array of objects with path and content. " | |
| "For Python web apps, use Flask, read PORT from os.environ, bind host 0.0.0.0, and keep dependencies to installed packages when possible. " | |
| "Do not include markdown fences." | |
| ) | |
| try: | |
| llm_result = call_llm( | |
| prompt, | |
| system=system, | |
| temperature=float(data.get("temperature", 0.25)), | |
| max_tokens=int(data.get("max_tokens", 2600)), | |
| timeout=data.get("timeout", 120), | |
| response_format={"type": "json_object"}, | |
| ) | |
| try: | |
| app_spec = parse_llm_json(llm_result["response"]) | |
| except Exception as first_error: | |
| repair = call_llm( | |
| "Repair this into strict valid JSON only. It must contain name, description, start_command, and files. " | |
| "Every files[].content value must be a properly escaped JSON string.\n\n" | |
| f"{llm_result['response']}", | |
| system=system, | |
| temperature=0, | |
| max_tokens=int(data.get("max_tokens", 2600)), | |
| timeout=data.get("timeout", 120), | |
| response_format={"type": "json_object"}, | |
| ) | |
| llm_result = repair | |
| try: | |
| app_spec = parse_llm_json(llm_result["response"]) | |
| except Exception as repair_error: | |
| app_spec = fallback_app_spec(prompt, reason=f"LLM JSON repair failed: {first_error}; {repair_error}") | |
| except ValueError as e: | |
| return jsonify({"error": str(e)}), 400 | |
| except Exception as e: | |
| return jsonify({"error": f"LLM app generation failed: {e}"}), 502 | |
| app_spec = normalize_generated_app_spec(app_spec, prompt=prompt) | |
| created = create_generated_app(app_spec) | |
| if created.get("error"): | |
| return jsonify({"error": created["error"], "llm_response": llm_result.get("response")}), 400 | |
| if bool(data.get("run", True)): | |
| started, status = start_generated_app(created["app_id"]) | |
| created.update(started) | |
| add_memory( | |
| title=f"LLM-built backend: {created['name']}", | |
| content=f"prompt:\n{prompt}\n\napp:\n{json.dumps(created, indent=2)}", | |
| source="llm-app-builder", | |
| tags=["llm", "backend", "generated-app"], | |
| metadata={"app_id": created["app_id"], "model": llm_result["model"]}, | |
| importance=0.9, | |
| ) | |
| receipt = create_receipt( | |
| kind="prompt-to-backend", | |
| title=f"Prompt-to-backend: {created['name']}", | |
| status=created.get("status", "created"), | |
| prompt=prompt, | |
| app_record=created, | |
| model={"api_base": llm_result["api_base"], "model": llm_result["model"]}, | |
| command=created.get("start_command", ""), | |
| metadata={"loop": "prompt -> files -> process -> proxy -> memory", "llm_response_hash": sha256_text(llm_result.get("response", ""))}, | |
| ) | |
| created["receipt_id"] = receipt["receipt_id"] | |
| attach_receipt_to_app(created["app_id"], receipt["receipt_id"]) | |
| created["token_reward"] = maybe_credit(data, "agent_build", TOKEN_REWARDS["agent_build"]) | |
| return jsonify({"app": created, "receipt": receipt, "llm": {"api_base": llm_result["api_base"], "model": llm_result["model"]}}), 201 | |
| def deploy_command(provider: str, data: dict) -> tuple[str, str]: | |
| deploy_cfg = settings.get("deploy", {}) | |
| if provider == "vercel": | |
| token = settings.get("env", {}).get("VERCEL_TOKEN") or os.environ.get("VERCEL_TOKEN") | |
| if not token: | |
| raise ValueError("VERCEL_TOKEN is not configured in settings.") | |
| project_dir = str(data.get("project_dir") or deploy_cfg.get("vercel_project_dir") or runtime_cwd()) | |
| prod = bool(data.get("prod", True)) | |
| cmd = f"vercel deploy --yes {'--prod' if prod else ''} --token \"$VERCEL_TOKEN\"" | |
| return cmd, project_dir | |
| if provider == "netlify": | |
| token = settings.get("env", {}).get("NETLIFY_AUTH_TOKEN") or os.environ.get("NETLIFY_AUTH_TOKEN") | |
| if not token: | |
| raise ValueError("NETLIFY_AUTH_TOKEN is not configured in settings.") | |
| project_dir = str(data.get("project_dir") or deploy_cfg.get("netlify_project_dir") or runtime_cwd()) | |
| publish_dir = str(data.get("publish_dir") or deploy_cfg.get("netlify_publish_dir") or project_dir) | |
| prod = bool(data.get("prod", True)) | |
| cmd = f"netlify deploy --dir \"{publish_dir}\" {'--prod' if prod else ''} --auth \"$NETLIFY_AUTH_TOKEN\"" | |
| if data.get("site"): | |
| cmd += f" --site \"{data['site']}\"" | |
| return cmd, project_dir | |
| raise ValueError(f"Unsupported provider: {provider}") | |
| # ββ Stripe ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def get_app_origin() -> str: | |
| """Return the full HTTPS app origin for Stripe redirects.""" | |
| configured = settings.get("env", {}).get("APP_ORIGIN") or os.environ.get("APP_ORIGIN", "") | |
| if configured: | |
| return configured.rstrip("/") | |
| # Fallback to request origin if available | |
| if request: | |
| host = request.headers.get("X-Forwarded-Host") or request.headers.get("Host", "") | |
| proto = request.headers.get("X-Forwarded-Proto", "https") | |
| if host: | |
| return f"{proto}://{host}" | |
| return "https://localhost" | |
| def stripe_config(): | |
| """Public endpoint returning safe Stripe config (publishable key + origin).""" | |
| pk = settings.get("env", {}).get("STRIPE_PUBLISHABLE_KEY") or os.environ.get("STRIPE_PUBLISHABLE_KEY", "") | |
| return jsonify({ | |
| "publishable_key": pk, | |
| "origin": get_app_origin(), | |
| "status": "ready" if pk else "missing_publishable_key", | |
| }) | |
| def stripe_checkout(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| import stripe as stripe_lib | |
| sk = settings.get("env", {}).get("STRIPE_SECRET_KEY") or os.environ.get("STRIPE_SECRET_KEY", "") | |
| if not sk: | |
| return jsonify({"error": "Stripe secret key not configured"}), 400 | |
| stripe_lib.api_key = sk | |
| data = request.json or {} | |
| origin = get_app_origin() | |
| success_url = f"{origin}/?session_id={{CHECKOUT_SESSION_ID}}#success" | |
| cancel_url = f"{origin}/?canceled=true" | |
| try: | |
| session = stripe_lib.checkout.Session.create( | |
| payment_method_types=["card"], | |
| line_items=[{ | |
| "price_data": { | |
| "currency": str(data.get("currency", "usd")), | |
| "product_data": {"name": str(data.get("product_name", "HF VM Studio Service"))}, | |
| "unit_amount": int(data.get("amount_cents", 500)), | |
| }, | |
| "quantity": int(data.get("quantity", 1)), | |
| }], | |
| mode="payment", | |
| success_url=success_url, | |
| cancel_url=cancel_url, | |
| metadata={ | |
| "source": "hf-vm-studio", | |
| "user_tag": str(data.get("user_tag", "")), | |
| }, | |
| ) | |
| receipt = create_receipt( | |
| kind="stripe-checkout", | |
| title=f"Stripe checkout created: {data.get('product_name', 'Service')}", | |
| status="created", | |
| command=f"checkout_session:{session.id}", | |
| metadata={ | |
| "session_id": session.id, | |
| "amount_cents": data.get("amount_cents", 500), | |
| "currency": data.get("currency", "usd"), | |
| "origin": origin, | |
| }, | |
| ) | |
| return jsonify({ | |
| "session_id": session.id, | |
| "url": session.url, | |
| "receipt_id": receipt["receipt_id"], | |
| }) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 502 | |
| def stripe_webhook(): | |
| import stripe as stripe_lib | |
| sk = settings.get("env", {}).get("STRIPE_SECRET_KEY") or os.environ.get("STRIPE_SECRET_KEY", "") | |
| if not sk: | |
| return jsonify({"error": "Stripe secret key not configured"}), 400 | |
| payload = request.get_data(as_text=True) | |
| sig_header = request.headers.get("Stripe-Signature", "") | |
| webhook_secret = settings.get("env", {}).get("STRIPE_WEBHOOK_SECRET") or os.environ.get("STRIPE_WEBHOOK_SECRET", "") | |
| try: | |
| if webhook_secret: | |
| event = stripe_lib.Webhook.construct_event(payload, sig_header, webhook_secret) | |
| else: | |
| event = json.loads(payload) | |
| except Exception as e: | |
| return jsonify({"error": f"Webhook verification failed: {e}"}), 400 | |
| event_type = event.get("type", "unknown") | |
| obj = event.get("data", {}).get("object", {}) | |
| session_id = str(obj.get("id", "")) | |
| now = datetime.now(timezone.utc).isoformat() | |
| period = now[:7] | |
| # ββ Idempotency guard βββββββββββββββββββββββββββββββββββββββββ | |
| with token_lock: | |
| with _db() as conn: | |
| processed = conn.execute("SELECT session_id, tx_id FROM stripe_sessions WHERE session_id = ?", (session_id,)).fetchone() | |
| if processed: | |
| logger.info("Stripe webhook idempotent skip: session=%s already processed with tx=%s", session_id, processed["tx_id"]) | |
| return jsonify({"received": True, "type": event_type, "idempotent": True, "session_id": session_id}), 200 | |
| # ββ Token purchase fulfillment ββββββββββββββββββββββββββββββ | |
| credited = None | |
| if event_type in ("checkout.session.completed", "checkout.session.async_payment_succeeded"): | |
| metadata = obj.get("metadata", {}) | |
| if metadata.get("source") == "hf-vm-studio" and metadata.get("wallet"): | |
| wallet = str(metadata["wallet"]).lower() | |
| # Integer tokens only β no floats for money (C53) | |
| tokens_str = str(metadata.get("tokens", "0")).strip() | |
| try: | |
| tokens = int(tokens_str) | |
| except ValueError: | |
| tokens = 0 | |
| amount_cents = int(obj.get("amount_total", 0)) | |
| currency = str(obj.get("currency", "usd")).lower() | |
| pack = str(metadata.get("pack", "unknown")) | |
| if tokens > 0: | |
| tx_id = f"stripe_{session_id}" | |
| credited = credit_tokens( | |
| wallet, tokens, | |
| reason=f"stripe_purchase:{pack}", | |
| metadata={"session_id": session_id, "pack": pack, "currency": currency}, | |
| idempotency_key=tx_id, | |
| revenue_cents=amount_cents, | |
| ) | |
| # Record processed session for idempotency | |
| with token_lock: | |
| with _db() as conn: | |
| conn.execute( | |
| "INSERT INTO stripe_sessions (session_id, event_type, status, amount_cents, currency, wallet, pack, tokens, processed_at, tx_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | |
| (session_id, event_type, "completed", amount_cents, currency, wallet, pack, tokens, now, tx_id), | |
| ) | |
| # Revenue ledger entry | |
| rev_id = f"rev_{uuid.uuid4().hex}" | |
| conn.execute( | |
| "INSERT INTO revenue (revenue_id, source, session_id, amount_cents, currency, period, wallet, created_at, metadata) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", | |
| (rev_id, "stripe_webhook", session_id, amount_cents, currency, period, wallet, now, json.dumps({"pack": pack, "tokens": tokens, "event_type": event_type})), | |
| ) | |
| conn.commit() | |
| add_memory( | |
| title=f"Stripe webhook: {event_type}", | |
| content=json.dumps(event, indent=2)[:5000], | |
| source="stripe-webhook", | |
| tags=["stripe", event_type], | |
| metadata={"session_id": session_id, "event_type": event_type, "tokens_credited": credited}, | |
| importance=0.85, | |
| ) | |
| create_receipt( | |
| kind="stripe-webhook", | |
| title=f"Stripe webhook: {event_type}", | |
| status="received", | |
| command=f"webhook:{event_type}:{session_id}", | |
| metadata={"session_id": session_id, "event_type": event_type, "tokens_credited": credited}, | |
| ) | |
| return jsonify({"received": True, "type": event_type, "tokens_credited": credited, "session_id": session_id}) | |
| def deploy_vercel(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"deploy:{request.remote_addr}", window=60, max_requests=5): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| try: | |
| cmd, cwd = deploy_command("vercel", data) | |
| except ValueError as e: | |
| return jsonify({"error": str(e)}), 400 | |
| result = launch_background_process(cmd, timeout=int(data.get("timeout", 0) or 0), cwd=cwd) | |
| result["provider"] = "vercel" | |
| receipt = create_receipt( | |
| kind="deployment", | |
| title="Vercel deployment launched", | |
| status="launched", | |
| command=redact_command_secret(cmd, os.environ.get("VERCEL_TOKEN", "")), | |
| process=result, | |
| deployment={"provider": "vercel", "project_dir": cwd, "prod": bool(data.get("prod", True))}, | |
| metadata={"process_id": result.get("process_id")}, | |
| ) | |
| result["receipt_id"] = receipt["receipt_id"] | |
| result["token_reward"] = maybe_credit(data, "deploy", TOKEN_REWARDS["deploy"]) | |
| return jsonify(result), 202 | |
| def deploy_netlify(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"deploy:{request.remote_addr}", window=60, max_requests=5): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| try: | |
| cmd, cwd = deploy_command("netlify", data) | |
| except ValueError as e: | |
| return jsonify({"error": str(e)}), 400 | |
| result = launch_background_process(cmd, timeout=int(data.get("timeout", 0) or 0), cwd=cwd) | |
| result["provider"] = "netlify" | |
| receipt = create_receipt( | |
| kind="deployment", | |
| title="Netlify deployment launched", | |
| status="launched", | |
| command=redact_command_secret(cmd, os.environ.get("NETLIFY_AUTH_TOKEN", "")), | |
| process=result, | |
| deployment={"provider": "netlify", "project_dir": cwd, "publish_dir": data.get("publish_dir"), "prod": bool(data.get("prod", True))}, | |
| metadata={"process_id": result.get("process_id")}, | |
| ) | |
| result["receipt_id"] = receipt["receipt_id"] | |
| result["token_reward"] = maybe_credit(data, "deploy", TOKEN_REWARDS["deploy"]) | |
| return jsonify(result), 202 | |
| def execute_background(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| data = request.json or {} | |
| cmd = data.get("command", "").strip() | |
| timeout = int(data.get("timeout", 0) or 0) | |
| cwd = data.get("cwd") | |
| if not cmd: | |
| return jsonify({"error": "Missing command"}), 400 | |
| return jsonify(launch_background_process(cmd, timeout=timeout, cwd=cwd)), 202 | |
| def list_processes(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| return jsonify({"processes": [redact_process(p) for p in processes.values()]}) | |
| def get_process(process_id): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| proc = processes.get(process_id) | |
| if not proc: | |
| return jsonify({"error": "Process not found"}), 404 | |
| return jsonify(redact_process(proc)) | |
| def stop_process(process_id): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| proc = processes.get(process_id) | |
| if not proc: | |
| return jsonify({"error": "Process not found"}), 404 | |
| popen = proc.get("_popen") | |
| if popen and proc.get("status") == "running": | |
| try: | |
| if hasattr(os, "killpg"): | |
| os.killpg(os.getpgid(popen.pid), signal.SIGTERM) | |
| else: | |
| popen.terminate() | |
| proc["status"] = "stopping" | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| return jsonify(redact_process(proc)) | |
| def kernel_status(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| return jsonify({ | |
| "kernel_running": kernel_manager is not None, | |
| "cwd": str(DEFAULT_CWD), | |
| "kernel_name": "python3", | |
| }) | |
| def kernel_execute(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"kernel:{request.remote_addr}", window=60, max_requests=30): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| code = _clamp_str(data.get("code", ""), max_len=50000) | |
| timeout = data.get("timeout", 60) | |
| if not code.strip(): | |
| return jsonify({"error": "Missing code"}), 400 | |
| result = execute_kernel_code(code, timeout=timeout) | |
| add_memory( | |
| title="Kernel execution", | |
| content=f"code:\n{code}\nstdout:\n{result.get('stdout','')}\nstderr:\n{result.get('stderr','')}", | |
| source="kernel", | |
| tags=["jupyter", "kernel"], | |
| metadata={"success": result.get("success"), "display_data": bool(result.get("display_data"))}, | |
| importance=0.7, | |
| ) | |
| state["executed_tasks"].append({ | |
| "command": "kernel.execute", | |
| "timestamp": datetime.now(timezone.utc).isoformat(), | |
| "success": result["success"], | |
| }) | |
| state["executed_tasks"] = state["executed_tasks"][-1000:] | |
| save_state() | |
| receipt = create_receipt( | |
| kind="kernel", | |
| title="Jupyter kernel execution", | |
| status="success" if result.get("success") else "failed", | |
| command="kernel.execute", | |
| metadata={"code_hash": sha256_text(code), "result": result}, | |
| ) | |
| result["receipt_id"] = receipt["receipt_id"] | |
| result["token_reward"] = maybe_credit(data, "kernel_execute", TOKEN_REWARDS["kernel_execute"]) | |
| return jsonify(result) | |
| def kernel_restart(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| shutdown_kernel() | |
| get_kernel() | |
| return jsonify({"kernel_running": True, "status": "restarted"}) | |
| def notebook_run(): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"notebook:{request.remote_addr}", window=60, max_requests=15): | |
| return rate_limit_response() | |
| import nbformat | |
| data = request.json or {} | |
| cells = data.get("cells") | |
| if cells is None and data.get("code"): | |
| cells = [data["code"]] | |
| if not isinstance(cells, list) or not cells: | |
| return jsonify({"error": "Provide cells: [...] or code: '...'"}), 400 | |
| cells = [_clamp_str(c, max_len=50000) for c in cells] | |
| if len(cells) > 50: | |
| return jsonify({"error": "Too many cells (max 50)"}), 400 | |
| timeout = data.get("timeout", 60) | |
| notebook_id = f"nb_{uuid.uuid4().hex[:12]}" | |
| results = [] | |
| nb = nbformat.v4.new_notebook() | |
| nb_cells = [] | |
| for source in cells: | |
| source = str(source) | |
| result = execute_kernel_code(source, timeout=timeout) | |
| results.append(result) | |
| output_text = "" | |
| if result.get("stdout"): | |
| output_text += result["stdout"] | |
| if result.get("stderr"): | |
| output_text += result["stderr"] | |
| cell = nbformat.v4.new_code_cell(source=source) | |
| if output_text: | |
| cell.outputs = [nbformat.v4.new_output("stream", name="stdout", text=output_text)] | |
| nb_cells.append(cell) | |
| nb.cells = nb_cells | |
| path = NOTEBOOK_DIR / f"{notebook_id}.ipynb" | |
| nbformat.write(nb, path) | |
| add_memory( | |
| title=f"Notebook run: {notebook_id}", | |
| content="\n\n".join([f"cell:\n{source}" for source in cells]), | |
| source="notebook", | |
| tags=["notebook", "jupyter"], | |
| metadata={"notebook_id": notebook_id, "path": str(path), "success": all(r.get("success") for r in results)}, | |
| importance=0.75, | |
| ) | |
| response = { | |
| "notebook_id": notebook_id, | |
| "path": str(path), | |
| "success": all(r.get("success") for r in results), | |
| "results": results, | |
| } | |
| receipt = create_receipt( | |
| kind="notebook", | |
| title=f"Notebook run: {notebook_id}", | |
| status="success" if response["success"] else "failed", | |
| command="notebook.run", | |
| metadata={"notebook_id": notebook_id, "path": str(path), "cell_count": len(cells), "cells_hash": sha256_text(json.dumps(cells))}, | |
| ) | |
| response["receipt_id"] = receipt["receipt_id"] | |
| response["token_reward"] = maybe_credit(data, "notebook_run", TOKEN_REWARDS["notebook_run"]) | |
| return jsonify(response) | |
| def terminal_ui(): | |
| auth = require_auth() | |
| if auth: | |
| return Response( | |
| "Unauthorized. Open /terminal?token=YOUR_TERMINAL_AGENT_TOKEN", | |
| status=401, | |
| mimetype="text/plain", | |
| ) | |
| return render_template("terminal.html", | |
| brand_name="HF VM Studio", | |
| brand_tag="Prompt-to-Backend Factory", | |
| brand_emoji="β", | |
| ) | |
| # ββ Wallet & Tokens βββββββββββββββββββββββββββββββββββββββββββββ | |
| def wallet_nonce(): | |
| """Get a challenge nonce for wallet signature.""" | |
| if not _rate_check(f"nonce:{request.remote_addr}", window=60, max_requests=20): | |
| return rate_limit_response() | |
| n = _nonce() | |
| return jsonify({"nonce": n, "message": f"HF VM Studio auth: {n}"}) | |
| def _is_valid_evm_address(addr: str) -> bool: | |
| return bool(re.fullmatch(r"0x[a-f0-9]{40}", addr)) | |
| def _is_valid_solana_address(addr: str) -> bool: | |
| try: | |
| import base58 | |
| decoded = base58.b58decode(addr) | |
| return len(decoded) == 32 | |
| except Exception: | |
| return False | |
| def wallet_connect(): | |
| """Register a wallet connection with cryptographic signature verification.""" | |
| data = request.json or {} | |
| raw_address = _clamp_str(data.get("address", ""), 128).strip() | |
| provider = str(data.get("provider", "")).strip().lower() | |
| signature = _clamp_str(data.get("signature", ""), 2048).strip() | |
| nonce = _clamp_str(data.get("nonce", ""), 128).strip() | |
| if not raw_address or not provider: | |
| return jsonify({"error": "address and provider required"}), 400 | |
| if provider not in ("metamask", "phantom"): | |
| return jsonify({"error": "provider must be metamask or phantom"}), 400 | |
| # EVM: lowercase; Solana: preserve base58 case | |
| address = raw_address.lower() if provider == "metamask" else raw_address | |
| if provider == "metamask" and not _is_valid_evm_address(address): | |
| return jsonify({"error": "Invalid EVM address format"}), 400 | |
| if provider == "phantom" and not _is_valid_solana_address(address): | |
| return jsonify({"error": "Invalid Solana address format"}), 400 | |
| if not _rate_check(f"wallet_connect:{request.remote_addr}", window=3600, max_requests=10): | |
| return rate_limit_response() | |
| if not signature or not nonce: | |
| return jsonify({"error": "signature and nonce required"}), 400 | |
| # Verify signature | |
| verified = False | |
| if provider == "metamask": | |
| verified = _verify_evm_signature(address, signature, nonce) | |
| elif provider == "phantom": | |
| verified = _verify_solana_signature(address, signature, nonce) | |
| if not verified: | |
| return jsonify({"error": "Signature verification failed"}), 401 | |
| now = datetime.now(timezone.utc).isoformat() | |
| with wallet_lock: | |
| with _db() as conn: | |
| existing = conn.execute("SELECT address FROM wallets WHERE address = ?", (address,)).fetchone() | |
| is_new = existing is None | |
| conn.execute( | |
| "INSERT OR REPLACE INTO wallets (address, provider, signature, nonce, connected_at, last_seen) VALUES (?, ?, ?, ?, COALESCE((SELECT connected_at FROM wallets WHERE address = ?), ?), ?)", | |
| (address, provider, signature, nonce, address, now, now), | |
| ) | |
| conn.commit() | |
| welcome_bonus = 0 | |
| if is_new: | |
| welcome_bonus = 1000 # 1000 integer tokens welcome bonus | |
| credit_tokens(address, welcome_bonus, "welcome_bonus") | |
| return jsonify({ | |
| "wallet": address, | |
| "provider": provider, | |
| "verified": True, | |
| "balance": get_balance(address), | |
| "welcome_bonus": welcome_bonus, | |
| }) | |
| def wallet_info(address): | |
| """Get wallet balance and connection info.""" | |
| addr = _normalize_wallet(address) | |
| with wallet_lock: | |
| with _db() as conn: | |
| row = conn.execute("SELECT * FROM wallets WHERE address = ?", (addr,)).fetchone() | |
| if not row: | |
| return jsonify({"wallet": addr, "balance": 0, "connected": False}), 404 | |
| return jsonify({ | |
| "wallet": addr, | |
| "balance": get_balance(addr), | |
| "provider": row["provider"], | |
| "connected_at": row["connected_at"], | |
| "last_seen": row["last_seen"], | |
| "connected": True, | |
| }) | |
| def wallet_history(address): | |
| """Get token transaction history for a wallet.""" | |
| addr = _normalize_wallet(address) | |
| limit = max(1, min(int(request.args.get("limit", 50)), 200)) | |
| return jsonify({"wallet": addr, "transactions": tx_history(addr, limit)}) | |
| def tokens_leaderboard(): | |
| limit = max(1, min(int(request.args.get("limit", 20)), 100)) | |
| return jsonify({"leaderboard": leaderboard(limit)}) | |
| def tokens_buy(): | |
| """Create a Stripe checkout to buy token packs.""" | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"tokens_buy:{request.remote_addr}", window=60, max_requests=10): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| raw_wallet = str(data.get("wallet_address", "")).strip() | |
| # Detect address type: EVM starts with 0x, Solana is base58 | |
| is_evm = raw_wallet.startswith("0x") | |
| wallet = raw_wallet.lower() if is_evm else raw_wallet | |
| if is_evm and not _is_valid_evm_address(wallet): | |
| return jsonify({"error": "Invalid EVM wallet address"}), 400 | |
| if not is_evm and not _is_valid_solana_address(wallet): | |
| return jsonify({"error": "Invalid Solana wallet address"}), 400 | |
| if not _rate_check(f"tokens_buy_wallet:{wallet}", window=3600, max_requests=5): | |
| return rate_limit_response() | |
| pack = str(data.get("pack", "small")).strip().lower() | |
| packs = { | |
| "small": {"amount_cents": 500, "tokens": 100, "label": "100 Tokens"}, | |
| "medium": {"amount_cents": 2000, "tokens": 500, "label": "500 Tokens"}, | |
| "large": {"amount_cents": 5000, "tokens": 1500, "label": "1500 Tokens"}, | |
| } | |
| if pack not in packs: | |
| return jsonify({"error": f"Unknown pack: {pack}. Choose small, medium, or large."}), 400 | |
| selected = packs[pack] | |
| import stripe as stripe_lib | |
| sk = settings.get("env", {}).get("STRIPE_SECRET_KEY") or os.environ.get("STRIPE_SECRET_KEY", "") | |
| if not sk: | |
| return jsonify({"error": "Stripe secret key not configured"}), 400 | |
| stripe_lib.api_key = sk | |
| origin = get_app_origin() | |
| try: | |
| session = stripe_lib.checkout.Session.create( | |
| payment_method_types=["card"], | |
| line_items=[{ | |
| "price_data": { | |
| "currency": "usd", | |
| "product_data": {"name": f"HF VM Studio β {selected['label']}"}, | |
| "unit_amount": selected["amount_cents"], | |
| }, | |
| "quantity": 1, | |
| }], | |
| mode="payment", | |
| success_url=f"{origin}/?session_id={{CHECKOUT_SESSION_ID}}&wallet={wallet}&pack={pack}#tokens", | |
| cancel_url=f"{origin}/?canceled=true#tokens", | |
| metadata={ | |
| "source": "hf-vm-studio", | |
| "wallet": wallet, | |
| "pack": pack, | |
| "tokens": str(selected["tokens"]), | |
| }, | |
| ) | |
| receipt = create_receipt( | |
| kind="token-purchase", | |
| title=f"Token purchase initiated: {selected['label']}", | |
| status="created", | |
| command=f"checkout_session:{session.id}", | |
| metadata={"session_id": session.id, "wallet": wallet, "pack": pack, "tokens": selected["tokens"]}, | |
| ) | |
| return jsonify({ | |
| "session_id": session.id, | |
| "url": session.url, | |
| "receipt_id": receipt["receipt_id"], | |
| "pack": pack, | |
| "tokens": selected["tokens"], | |
| "amount_cents": selected["amount_cents"], | |
| }) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 502 | |
| # ββ Solana Token Launch Service βββββββββββββββββββββββββββββββββ | |
| def _service_keypair_path() -> str: | |
| """Persist service keypair to disk for CLI use.""" | |
| if not SOLANA_SERVICE_KEY_B58: | |
| raise ValueError("SOLANA_SERVICE_KEY_B58 not configured") | |
| import base58 as b58 | |
| kp_path = Path("service_keypair.json") | |
| if kp_path.exists(): | |
| return str(kp_path) | |
| secret = b58.b58decode(SOLANA_SERVICE_KEY_B58) | |
| # Phantom / solana-keygen exports 64 bytes [32 secret + 32 pubkey] | |
| if len(secret) not in (32, 64): | |
| raise ValueError("Invalid service keypair length") | |
| from solders.keypair import Keypair | |
| if len(secret) == 64: | |
| kp = Keypair.from_bytes(secret) | |
| else: | |
| kp = Keypair.from_seed(secret) | |
| arr = list(bytes(kp)) | |
| kp_path.write_text(json.dumps(arr)) | |
| return str(kp_path) | |
| def _solana_cli(cmd: list[str], timeout: int = 60) -> dict: | |
| """Run a Solana CLI command with configured RPC and keypair.""" | |
| kp = _service_keypair_path() | |
| full = ["solana", "--url", SOLANA_RPC_URL, "--keypair", kp] + cmd | |
| result = subprocess.run(full, capture_output=True, text=True, timeout=timeout) | |
| return { | |
| "stdout": result.stdout, | |
| "stderr": result.stderr, | |
| "rc": result.returncode, | |
| } | |
| def _spl_token_cli(cmd: list[str], timeout: int = 60) -> dict: | |
| """Run spl-token CLI with configured RPC and fee-payer.""" | |
| kp = _service_keypair_path() | |
| full = ["spl-token", "--url", SOLANA_RPC_URL, "--owner", kp, "--fee-payer", kp] + cmd | |
| result = subprocess.run(full, capture_output=True, text=True, timeout=timeout) | |
| return { | |
| "stdout": result.stdout, | |
| "stderr": result.stderr, | |
| "rc": result.returncode, | |
| } | |
| def launch_spl_token(owner_address: str, name: str, symbol: str, decimals: int, supply: int) -> dict: | |
| """Launch a new SPL token on Solana. Returns mint address and tx signature.""" | |
| if not SOLANA_SERVICE_KEY_B58: | |
| raise ValueError("SOLANA_SERVICE_KEY_B58 not configured; token launch unavailable") | |
| if SOLANA_MAINNET_ENABLED: | |
| logger.warning("Token launch executing on SOLANA MAINNET") | |
| now = datetime.now(timezone.utc).isoformat() | |
| launch_id = _new_tx_id() | |
| # Generate mint keypair | |
| from solders.keypair import Keypair | |
| mint_kp = Keypair() | |
| mint_path = Path(f"mint_{launch_id}.json") | |
| mint_path.write_text(json.dumps(list(bytes(mint_kp)))) | |
| try: | |
| # Create token mint | |
| create_res = _spl_token_cli(["create-token", str(mint_path), "--decimals", str(decimals)]) | |
| if create_res["rc"] != 0: | |
| raise RuntimeError(f"create-token failed: {create_res['stderr']}") | |
| # Extract mint address from output | |
| mint_addr = None | |
| for line in create_res["stdout"].splitlines(): | |
| if "Creating token" in line: | |
| parts = line.split() | |
| if len(parts) >= 3: | |
| mint_addr = parts[-1] | |
| if line.startswith("Address:"): | |
| mint_addr = line.split("Address:")[1].strip() | |
| if not mint_addr: | |
| # Fallback: use pubkey from keypair | |
| mint_addr = str(mint_kp.pubkey()) | |
| # Create associated token account for owner | |
| ata_res = _spl_token_cli(["create-account", mint_addr]) | |
| if ata_res["rc"] != 0: | |
| logger.warning(f"create-account warning: {ata_res['stderr']}") | |
| # Get ATA address | |
| ata_addr = owner_address # For simple transfer, we need the ATA | |
| # Actually spl-token create-account creates an ATA for the fee-payer | |
| # We need to create an ATA for the owner_address instead | |
| ata_for_owner = _spl_token_cli(["address", "--token", mint_addr, "--owner", owner_address]) | |
| owner_ata = None | |
| for line in ata_for_owner["stdout"].splitlines(): | |
| if line.startswith("Associated token address"): | |
| owner_ata = line.split(":")[-1].strip() | |
| if not owner_ata: | |
| # Create ATA for the actual owner | |
| create_ata = _spl_token_cli(["create-account", mint_addr, "--owner", owner_address]) | |
| if create_ata["rc"] != 0: | |
| logger.warning(f"create-account for owner warning: {create_ata['stderr']}") | |
| # Try to extract ATA | |
| for line in create_ata["stdout"].splitlines(): | |
| if line.startswith("Creating associated token account"): | |
| owner_ata = line.split()[-1].strip() | |
| if not owner_ata: | |
| owner_ata = owner_address # Fallback (will likely fail but recorded) | |
| # Mint tokens to owner | |
| mint_res = _spl_token_cli(["mint", mint_addr, str(supply), owner_ata]) | |
| if mint_res["rc"] != 0: | |
| raise RuntimeError(f"mint failed: {mint_res['stderr']}") | |
| # Record in DB | |
| with token_lock: | |
| with _db() as conn: | |
| conn.execute( | |
| "INSERT INTO launched_tokens (launch_id, mint_address, owner_address, name, symbol, decimals, supply, tx_signature, network, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | |
| (launch_id, mint_addr, owner_address, name, symbol, decimals, supply, "", "mainnet" if SOLANA_MAINNET_ENABLED else "devnet", now), | |
| ) | |
| conn.commit() | |
| return { | |
| "launch_id": launch_id, | |
| "mint_address": mint_addr, | |
| "owner_ata": owner_ata, | |
| "network": "mainnet" if SOLANA_MAINNET_ENABLED else "devnet", | |
| "name": name, | |
| "symbol": symbol, | |
| "decimals": decimals, | |
| "supply": supply, | |
| } | |
| finally: | |
| # Cleanup temp keypair | |
| if mint_path.exists(): | |
| mint_path.unlink() | |
| def tokens_launch(): | |
| """Launch a new SPL token on Solana. Costs tokens from user balance.""" | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"token_launch:{request.remote_addr}", window=3600, max_requests=3): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| raw_owner = _clamp_str(data.get("owner_address", ""), 128).strip() | |
| name = _clamp_str(data.get("name", ""), 64).strip() | |
| symbol = _clamp_str(data.get("symbol", ""), 16).strip().upper() | |
| decimals = max(0, min(int(data.get("decimals", 9)), 18)) | |
| supply = max(1, int(data.get("supply", 1_000_000_000))) | |
| if not raw_owner: | |
| return jsonify({"error": "owner_address required"}), 400 | |
| if not name or not symbol: | |
| return jsonify({"error": "name and symbol required"}), 400 | |
| if not _is_valid_solana_address(raw_owner): | |
| return jsonify({"error": "Invalid Solana owner address"}), 400 | |
| owner = _normalize_wallet(raw_owner) | |
| cost = _get_token_cost("token_launch") | |
| bal = get_balance(owner) | |
| if bal < cost: | |
| return jsonify({"error": f"Insufficient tokens. Need {cost}, have {bal}."}), 402 | |
| try: | |
| # Debit launch cost | |
| debit_tokens(owner, cost, "token_launch") | |
| result = launch_spl_token(owner, name, symbol, decimals, supply) | |
| result["cost"] = cost | |
| result["balance_after"] = get_balance(owner) | |
| create_receipt( | |
| kind="token-launch", | |
| title=f"Launched {symbol} on {result['network']}", | |
| status="completed", | |
| metadata=result, | |
| ) | |
| return jsonify(result), 201 | |
| except ValueError as e: | |
| return jsonify({"error": str(e)}), 400 | |
| except RuntimeError as e: | |
| return jsonify({"error": str(e)}), 502 | |
| except Exception as e: | |
| logger.exception("Token launch failed") | |
| return jsonify({"error": "Token launch failed. Check logs."}), 500 | |
| def tokens_launched(): | |
| """List launched tokens for a wallet.""" | |
| wallet = request.args.get("wallet", "").strip() | |
| limit = max(1, min(int(request.args.get("limit", 20)), 100)) | |
| if not wallet: | |
| return jsonify({"error": "wallet query param required"}), 400 | |
| addr = _normalize_wallet(wallet) | |
| with token_lock: | |
| with _db() as conn: | |
| rows = conn.execute( | |
| "SELECT * FROM launched_tokens WHERE owner_address = ? ORDER BY created_at DESC LIMIT ?", | |
| (addr, limit), | |
| ).fetchall() | |
| return jsonify({ | |
| "wallet": addr, | |
| "tokens": [dict(r) for r in rows], | |
| "network": "mainnet" if SOLANA_MAINNET_ENABLED else "devnet", | |
| }) | |
| # ββ CLAIMOS API ββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def claimos_evaluate(): | |
| """Create or evaluate a claim: POST evidence + signals, get probability state + receipt.""" | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"claimos_evaluate:{request.remote_addr}", window=60, max_requests=10): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| claim_id = str(data.get("claim_id", f"claim_{uuid.uuid4().hex}")).strip() | |
| title = str(data.get("title", "Untitled Claim")).strip() | |
| description = str(data.get("description", "")).strip()[:2000] | |
| wallet = str(data.get("wallet", "")).strip() | |
| # Upsert claim | |
| now = datetime.now(timezone.utc).isoformat() | |
| with _db() as conn: | |
| existing = conn.execute("SELECT claim_id FROM claims WHERE claim_id = ?", (claim_id,)).fetchone() | |
| if not existing: | |
| conn.execute( | |
| "INSERT INTO claims (claim_id, title, description, status, created_at, updated_at, wallet) VALUES (?, ?, ?, ?, ?, ?, ?)", | |
| (claim_id, title, description, "evidence_received", now, now, wallet or None), | |
| ) | |
| else: | |
| conn.execute( | |
| "UPDATE claims SET title = ?, description = ?, updated_at = ? WHERE claim_id = ?", | |
| (title, description, now, claim_id), | |
| ) | |
| conn.commit() | |
| # Store evidence items | |
| evidence_items = data.get("evidence", []) | |
| if evidence_items: | |
| with _db() as conn: | |
| for ev in evidence_items: | |
| ev_id = str(ev.get("evidence_id", f"ev_{uuid.uuid4().hex}")).strip() | |
| source_type = str(ev.get("source_type", "other")).strip().lower() | |
| if source_type not in ("audio","document","transcript","witness","hospital","police","screenshot","email","timeline","other"): | |
| source_type = "other" | |
| source_ref = str(ev.get("source_ref", "")).strip()[:500] | |
| content = str(ev.get("content", "")).strip()[:4000] | |
| content_hash = hashlib.sha256(content.encode("utf-8")).hexdigest() | |
| strength = float(ev.get("evidence_strength", 0.5)) | |
| conn.execute( | |
| """INSERT OR REPLACE INTO evidence | |
| (evidence_id, claim_id, source_type, source_ref, content_hash, content, evidence_strength, created_at) | |
| VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", | |
| (ev_id, claim_id, source_type, source_ref, content_hash, content, strength, now), | |
| ) | |
| conn.commit() | |
| # Debit tokens for evaluation | |
| if wallet: | |
| addr = _normalize_wallet(wallet) | |
| bal = get_balance(addr) | |
| cost = _get_token_cost("claim_evaluate") | |
| if bal < cost: | |
| return jsonify({"error": f"Insufficient tokens. Need {cost}, have {bal}"}), 402 | |
| debit_tokens(addr, cost, "claim_evaluate", {"claim_id": claim_id}) | |
| # Evaluate probability | |
| try: | |
| inputs = { | |
| "evidence_strength": data.get("evidence_strength"), | |
| "counsel_signal": data.get("counsel_signal"), | |
| "procedural_survival": data.get("procedural_survival"), | |
| "settlement_signal": data.get("settlement_signal"), | |
| "uncertainty": data.get("uncertainty"), | |
| } | |
| inputs = {k: float(v) for k, v in inputs.items() if v is not None} | |
| prob = ClaimProbabilityEngine.evaluate(claim_id, inputs if inputs else None) | |
| except ValueError as e: | |
| return jsonify({"error": str(e)}), 404 | |
| # Create proof receipt | |
| receipt = create_receipt( | |
| kind="claim-evaluation", | |
| title=f"Claim evaluated: {title}", | |
| status="completed", | |
| command=f"claimos_evaluate:{claim_id}", | |
| metadata={"claim_id": claim_id, "p_recovery": prob["p_recovery"], "wallet": wallet}, | |
| ) | |
| return jsonify({ | |
| "claim_id": claim_id, | |
| "probability_state": prob, | |
| "receipt_id": receipt["receipt_id"], | |
| "tokens_debited": _get_token_cost("claim_evaluate") if wallet else 0, | |
| }) | |
| def claimos_get(claim_id: str): | |
| """Get full claim state including evidence and contradictions.""" | |
| if not _rate_check(f"claimos_get:{request.remote_addr}", window=60, max_requests=30): | |
| return rate_limit_response() | |
| with _db() as conn: | |
| claim = conn.execute("SELECT * FROM claims WHERE claim_id = ?", (claim_id,)).fetchone() | |
| if not claim: | |
| return jsonify({"error": "Claim not found"}), 404 | |
| evidence = conn.execute("SELECT * FROM evidence WHERE claim_id = ?", (claim_id,)).fetchall() | |
| contradictions = conn.execute("SELECT * FROM contradictions WHERE claim_id = ? AND resolved = 0", (claim_id,)).fetchall() | |
| return jsonify({ | |
| "claim": dict(claim), | |
| "evidence": [dict(r) for r in evidence], | |
| "contradictions": [dict(r) for r in contradictions], | |
| }) | |
| def claimos_contradictions(claim_id: str): | |
| """Run contradiction scan on a claim. Costs tokens.""" | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"claimos_cx:{request.remote_addr}", window=60, max_requests=10): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| wallet = str(data.get("wallet", "")).strip() | |
| if wallet: | |
| addr = _normalize_wallet(wallet) | |
| bal = get_balance(addr) | |
| cost = _get_token_cost("claim_contradiction_scan") | |
| if bal < cost: | |
| return jsonify({"error": f"Insufficient tokens. Need {cost}, have {bal}"}), 402 | |
| debit_tokens(addr, cost, "claim_contradiction_scan", {"claim_id": claim_id}) | |
| cx = ContradictionDetector.detect(claim_id) | |
| receipt = create_receipt( | |
| kind="claim-contradiction-scan", | |
| title=f"Contradiction scan: {len(cx)} found", | |
| status="completed", | |
| command=f"claimos_contradictions:{claim_id}", | |
| metadata={"claim_id": claim_id, "contradictions_found": len(cx)}, | |
| ) | |
| return jsonify({ | |
| "claim_id": claim_id, | |
| "contradictions": cx, | |
| "contradiction_count": len(cx), | |
| "receipt_id": receipt["receipt_id"], | |
| "tokens_debited": _get_token_cost("claim_contradiction_scan") if wallet else 0, | |
| }) | |
| def claimos_greeks(claim_id: str): | |
| """Compute and return Claim Greeks (Ξ, Ξ, Ξ, V, K). Costs tokens if wallet provided.""" | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"claimos_greeks:{request.remote_addr}", window=60, max_requests=10): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| wallet = str(data.get("wallet", "")).strip() | |
| if wallet: | |
| addr = _normalize_wallet(wallet) | |
| bal = get_balance(addr) | |
| cost = _get_token_cost("claim_greeks") | |
| if bal < cost: | |
| return jsonify({"error": f"Insufficient tokens. Need {cost}, have {bal}"}), 402 | |
| debit_tokens(addr, cost, "claim_greeks", {"claim_id": claim_id}) | |
| try: | |
| greeks = ClaimGreeks.compute(claim_id) | |
| except ValueError as e: | |
| return jsonify({"error": str(e)}), 404 | |
| receipt = create_receipt( | |
| kind="claim-greeks", | |
| title="Claim Greeks computed", | |
| status="completed", | |
| command=f"claimos_greeks:{claim_id}", | |
| metadata={"claim_id": claim_id, "greeks": greeks}, | |
| ) | |
| return jsonify({ | |
| "claim_id": claim_id, | |
| "greeks": greeks, | |
| "receipt_id": receipt["receipt_id"], | |
| "tokens_debited": _get_token_cost("claim_greeks") if wallet else 0, | |
| }) | |
| def claimos_liquidity(claim_id: str): | |
| """Compute finance readiness / liquidity score for a claim.""" | |
| if not _rate_check(f"claimos_liq:{request.remote_addr}", window=60, max_requests=20): | |
| return rate_limit_response() | |
| try: | |
| liq = ClaimLiquidity.compute(claim_id) | |
| except ValueError as e: | |
| return jsonify({"error": str(e)}), 404 | |
| receipt = create_receipt( | |
| kind="claim-liquidity", | |
| title=f"Liquidity score: {liq['liquidity_score']:.4f}", | |
| status="completed", | |
| command=f"claimos_liquidity:{claim_id}", | |
| metadata={"claim_id": claim_id, "liquidity": liq["liquidity_score"]}, | |
| ) | |
| return jsonify({ | |
| "claim_id": claim_id, | |
| "liquidity": liq, | |
| "receipt_id": receipt["receipt_id"], | |
| }) | |
| def claimos_assess(claim_id: str): | |
| """Use LLM to assess evidence quality and auto-update evidence_strength scores. Costs tokens.""" | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"claimos_assess:{request.remote_addr}", window=60, max_requests=10): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| wallet = str(data.get("wallet", "")).strip() | |
| if wallet: | |
| addr = _normalize_wallet(wallet) | |
| bal = get_balance(addr) | |
| cost = _get_token_cost("claim_evaluate") | |
| if bal < cost: | |
| return jsonify({"error": f"Insufficient tokens. Need {cost}, have {bal}"}), 402 | |
| debit_tokens(addr, cost, "claim_assess", {"claim_id": claim_id}) | |
| with _db() as conn: | |
| rows = conn.execute("SELECT * FROM evidence WHERE claim_id = ?", (claim_id,)).fetchall() | |
| if not rows: | |
| return jsonify({"error": "No evidence found for claim"}), 404 | |
| # Build LLM prompt for evidence assessment | |
| ev_text = "\n\n".join( | |
| f"[{i+1}] {r['source_type'].upper()} (ref: {r['source_ref']}): {r['content'][:1000]}" | |
| for i, r in enumerate(rows) | |
| ) | |
| system_prompt = ( | |
| "You are a legal evidence assessor. Rate each evidence item on: credibility (0-1), " | |
| "relevance (0-1), completeness (0-1), and overall_strength (0-1). Return ONLY a JSON array " | |
| "where each item has: index (1-based), credibility, relevance, completeness, overall_strength, " | |
| "rationale (string). Be strict and realistic." | |
| ) | |
| try: | |
| result = call_llm(prompt=f"Assess the following evidence items for claim {claim_id}:\n\n{ev_text}", system=system_prompt, model="json") | |
| parsed = parse_llm_json(result.get("response", "[]")) | |
| if not isinstance(parsed, list): | |
| raise ValueError("LLM returned non-array") | |
| now = datetime.now(timezone.utc).isoformat() | |
| updated = [] | |
| with _db() as conn: | |
| for item in parsed: | |
| idx = int(item.get("index", 0)) - 1 | |
| if 0 <= idx < len(rows): | |
| ev_id = rows[idx]["evidence_id"] | |
| strength = round(min(1.0, max(0.0, float(item.get("overall_strength", 0.5)))), 4) | |
| conn.execute( | |
| "UPDATE evidence SET evidence_strength = ?, metadata = ? WHERE evidence_id = ?", | |
| (strength, json.dumps({"assessment": item}), ev_id), | |
| ) | |
| updated.append({"evidence_id": ev_id, "strength": strength, "rationale": item.get("rationale", "")}) | |
| conn.commit() | |
| receipt = create_receipt( | |
| kind="claim-assess", | |
| title=f"Evidence assessed: {len(updated)} items", | |
| status="completed", | |
| command=f"claimos_assess:{claim_id}", | |
| metadata={"claim_id": claim_id, "items_assessed": len(updated)}, | |
| ) | |
| return jsonify({ | |
| "claim_id": claim_id, | |
| "assessments": updated, | |
| "receipt_id": receipt["receipt_id"], | |
| "tokens_debited": _get_token_cost("claim_evaluate") if wallet else 0, | |
| }) | |
| except Exception as e: | |
| logger.warning(f"Claim assessment LLM failed: {e}") | |
| return jsonify({"error": f"LLM assessment failed: {e}"}), 502 | |
| def claimos_appraise(claim_id: str): | |
| """Generate a full legal appraisal report via LLM. Returns narrative + structured metrics.""" | |
| if not _rate_check(f"claimos_appraise:{request.remote_addr}", window=60, max_requests=5): | |
| return rate_limit_response() | |
| with _db() as conn: | |
| claim = conn.execute("SELECT * FROM claims WHERE claim_id = ?", (claim_id,)).fetchone() | |
| evidence = conn.execute("SELECT * FROM evidence WHERE claim_id = ?", (claim_id,)).fetchall() | |
| contradictions = conn.execute("SELECT * FROM contradictions WHERE claim_id = ? AND resolved = 0", (claim_id,)).fetchall() | |
| if not claim: | |
| return jsonify({"error": "Claim not found"}), 404 | |
| claim_data = dict(claim) | |
| ev_data = [dict(r) for r in evidence] | |
| cx_data = [dict(r) for r in contradictions] | |
| prompt = ( | |
| f"Generate a legal claim appraisal report.\n\n" | |
| f"CLAIM: {claim_data.get('title', '')}\n" | |
| f"DESCRIPTION: {claim_data.get('description', '')}\n" | |
| f"STATUS: {claim_data.get('status', '')}\n" | |
| f"P(RECOVERY): {claim_data.get('p_recovery', 0)}\n" | |
| f"EVIDENCE COUNT: {len(ev_data)}\n" | |
| f"CONTRADICTIONS: {len(cx_data)}\n\n" | |
| f"EVIDENCE:\n" + "\n".join( | |
| f"- {e['source_type']} ({e['source_ref']}): strength={e['evidence_strength']}" | |
| for e in ev_data[:10] | |
| ) + "\n\n" | |
| f"Return ONLY JSON with: summary (string), strengths (array), risks (array), " | |
| f"recommended_next_steps (array), settlement_likelihood (0-1), expected_recovery_range (string)." | |
| ) | |
| try: | |
| result = call_llm(prompt=prompt, system="You are a senior legal claim appraiser. Be concise, realistic, and structured.", model="quality") | |
| parsed = parse_llm_json(result.get("response", "{}")) | |
| if not isinstance(parsed, dict): | |
| parsed = {"summary": "Appraisal generated", "raw": result.get("response", "")} | |
| receipt = create_receipt( | |
| kind="claim-appraisal", | |
| title=f"Appraisal: {claim_data.get('title', claim_id)[:60]}", | |
| status="completed", | |
| command=f"claimos_appraise:{claim_id}", | |
| metadata={"claim_id": claim_id, "appraisal": parsed}, | |
| ) | |
| return jsonify({ | |
| "claim_id": claim_id, | |
| "appraisal": parsed, | |
| "probability_state": { | |
| "p_recovery": claim_data.get("p_recovery"), | |
| "liquidity_score": claim_data.get("liquidity_score"), | |
| "status": claim_data.get("status"), | |
| }, | |
| "receipt_id": receipt["receipt_id"], | |
| }) | |
| except Exception as e: | |
| logger.warning(f"Claim appraisal LLM failed: {e}") | |
| return jsonify({"error": f"Appraisal failed: {e}"}), 502 | |
| def tokens_verify(mint_address: str): | |
| """Verify an SPL token mint exists on-chain via Solana RPC. No simulation.""" | |
| if not _rate_check(f"token_verify:{request.remote_addr}", window=60, max_requests=20): | |
| return rate_limit_response() | |
| # Call Solana RPC getAccountInfo for the mint | |
| rpc_payload = { | |
| "jsonrpc": "2.0", | |
| "id": 1, | |
| "method": "getAccountInfo", | |
| "params": [mint_address, {"encoding": "jsonParsed"}], | |
| } | |
| try: | |
| resp = requests.post(SOLANA_RPC_URL, json=rpc_payload, timeout=15) | |
| resp.raise_for_status() | |
| data = resp.json() | |
| if data.get("error"): | |
| return jsonify({"mint": mint_address, "exists": False, "error": data["error"]}), 404 | |
| result = data.get("result", {}) | |
| value = result.get("value") | |
| if not value: | |
| return jsonify({"mint": mint_address, "exists": False, "on_chain": False}), 404 | |
| # Mint account exists β parse token data if available | |
| parsed = value.get("data", {}).get("parsed", {}).get("info", {}) if isinstance(value.get("data"), dict) else {} | |
| return jsonify({ | |
| "mint": mint_address, | |
| "exists": True, | |
| "on_chain": True, | |
| "rpc": SOLANA_RPC_URL, | |
| "lamports": value.get("lamports"), | |
| "owner": value.get("owner"), | |
| "executable": value.get("executable"), | |
| "parsed_info": parsed, | |
| "verified_at": datetime.now(timezone.utc).isoformat(), | |
| }) | |
| except Exception as e: | |
| logger.warning(f"Solana RPC verification failed for {mint_address}: {e}") | |
| return jsonify({"mint": mint_address, "exists": False, "error": str(e)}), 502 | |
| # ββ Finance / Underwriting Proof ββββββββββββββββββββββββββββββββ | |
| def finance_collateral(): | |
| """Underwriting proof: verifiable income, deferred revenue, token velocity.""" | |
| if not _rate_check(f"finance:{request.remote_addr}", window=60, max_requests=30): | |
| return rate_limit_response() | |
| with token_lock: | |
| with _db() as conn: | |
| # Total revenue | |
| rev_row = conn.execute("SELECT COALESCE(SUM(amount_cents), 0) AS total FROM revenue").fetchone() | |
| total_revenue_cents = rev_row["total"] if rev_row else 0 | |
| # Deferred revenue (outstanding token liability) | |
| def_row = conn.execute("SELECT COALESCE(SUM(deferred_cents), 0) AS total, COALESCE(SUM(tokens_purchased), 0) AS purchased, COALESCE(SUM(tokens_spent), 0) AS spent FROM deferred_revenue").fetchone() | |
| deferred_cents = def_row["total"] if def_row else 0 | |
| tokens_purchased = def_row["purchased"] if def_row else 0 | |
| tokens_spent = def_row["spent"] if def_row else 0 | |
| # Wallet count | |
| wallet_row = conn.execute("SELECT COUNT(*) AS cnt FROM wallets").fetchone() | |
| wallet_count = wallet_row["cnt"] if wallet_row else 0 | |
| # Active paying wallets (have purchased tokens) | |
| pay_row = conn.execute("SELECT COUNT(DISTINCT wallet) AS cnt FROM stripe_sessions").fetchone() | |
| paying_wallets = pay_row["cnt"] if pay_row else 0 | |
| # Period revenue (last 6 months) | |
| period_rows = conn.execute( | |
| "SELECT period, SUM(amount_cents) AS cents FROM revenue GROUP BY period ORDER BY period DESC LIMIT 6" | |
| ).fetchall() | |
| # Token velocity: spend rate | |
| vel_row = conn.execute( | |
| "SELECT COALESCE(SUM(amount), 0) AS spent FROM transactions WHERE type = 'debit' AND created_at > datetime('now', '-30 days')" | |
| ).fetchone() | |
| monthly_spend = vel_row["spent"] if vel_row else 0 | |
| return jsonify({ | |
| "underwriting_version": "1.0.0", | |
| "generated_at": datetime.now(timezone.utc).isoformat(), | |
| "total_revenue_usd": round(total_revenue_cents / 100, 2), | |
| "deferred_revenue_usd": round(deferred_cents / 100, 2), | |
| "recognized_revenue_usd": round((total_revenue_cents - deferred_cents) / 100, 2), | |
| "wallet_count": wallet_count, | |
| "paying_wallets": paying_wallets, | |
| "tokens_purchased": tokens_purchased, | |
| "tokens_spent": tokens_spent, | |
| "token_velocity_30d": monthly_spend, | |
| "revenue_by_period": [{"period": r["period"], "usd": round(r["cents"] / 100, 2)} for r in period_rows], | |
| "collateral_score": round(min(100, (total_revenue_cents / 1000) + (paying_wallets * 10) + (monthly_spend / 100)), 2), | |
| }) | |
| def finance_revenue(): | |
| """Revenue dashboard with period and source breakdown.""" | |
| if not _rate_check(f"finance:{request.remote_addr}", window=60, max_requests=30): | |
| return rate_limit_response() | |
| period_filter = request.args.get("period", "") | |
| source_filter = request.args.get("source", "") | |
| limit = max(1, min(int(request.args.get("limit", 100)), 500)) | |
| with token_lock: | |
| with _db() as conn: | |
| query = "SELECT * FROM revenue WHERE 1=1" | |
| params = [] | |
| if period_filter: | |
| query += " AND period = ?" | |
| params.append(period_filter) | |
| if source_filter: | |
| query += " AND source = ?" | |
| params.append(source_filter) | |
| query += " ORDER BY created_at DESC LIMIT ?" | |
| params.append(limit) | |
| rows = conn.execute(query, params).fetchall() | |
| # Aggregates | |
| agg = conn.execute("SELECT source, SUM(amount_cents) AS cents FROM revenue GROUP BY source").fetchall() | |
| return jsonify({ | |
| "entries": [{"revenue_id": r["revenue_id"], "source": r["source"], "amount_cents": r["amount_cents"], "currency": r["currency"], "period": r["period"], "wallet": r["wallet"], "created_at": r["created_at"]} for r in rows], | |
| "by_source": {r["source"]: r["cents"] for r in agg}, | |
| "total_usd": round(sum(r["cents"] for r in agg) / 100, 2), | |
| }) | |
| def finance_reconcile(): | |
| """Reconcile Stripe sessions with token credits and revenue ledger.""" | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"finance:{request.remote_addr}", window=60, max_requests=10): | |
| return rate_limit_response() | |
| with token_lock: | |
| with _db() as conn: | |
| # Find Stripe sessions without matching transactions | |
| orphan_sessions = conn.execute( | |
| """SELECT s.session_id, s.amount_cents, s.wallet, s.pack, s.tokens, s.tx_id | |
| FROM stripe_sessions s | |
| LEFT JOIN transactions t ON s.tx_id = t.tx_id | |
| WHERE t.tx_id IS NULL""" | |
| ).fetchall() | |
| # Find transactions without matching revenue | |
| orphan_tx = conn.execute( | |
| """SELECT t.tx_id, t.address, t.amount, t.reason | |
| FROM transactions t | |
| LEFT JOIN revenue r ON t.tx_id = r.session_id | |
| WHERE t.type = 'credit' AND r.revenue_id IS NULL AND t.reason LIKE 'stripe_purchase%'""" | |
| ).fetchall() | |
| return jsonify({ | |
| "orphan_stripe_sessions": len(orphan_sessions), | |
| "orphan_transactions": len(orphan_tx), | |
| "orphan_session_details": [{"session_id": s["session_id"], "wallet": s["wallet"], "tokens": s["tokens"]} for s in orphan_sessions], | |
| "reconciled": len(orphan_sessions) == 0 and len(orphan_tx) == 0, | |
| }) | |
| def finance_rollback(): | |
| """Rollback a transaction by tx_id. Returns tokens to wallet and reverses revenue.""" | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"finance:{request.remote_addr}", window=60, max_requests=5): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| tx_id = str(data.get("tx_id", "")).strip() | |
| reason = str(data.get("reason", "rollback")).strip() | |
| if not tx_id: | |
| return jsonify({"error": "tx_id required"}), 400 | |
| now = datetime.now(timezone.utc).isoformat() | |
| with token_lock: | |
| with _db() as conn: | |
| tx = conn.execute("SELECT * FROM transactions WHERE tx_id = ?", (tx_id,)).fetchone() | |
| if not tx: | |
| return jsonify({"error": "Transaction not found"}), 404 | |
| addr = tx["address"] | |
| amount = tx["amount"] | |
| tx_type = tx["type"] | |
| # Reverse the transaction | |
| if tx_type == "credit": | |
| # Was a credit β debit back | |
| bal_row = conn.execute("SELECT balance FROM balances WHERE address = ?", (addr,)).fetchone() | |
| current = bal_row["balance"] if bal_row else 0 | |
| if current < amount: | |
| return jsonify({"error": f"Cannot rollback: wallet balance {current} < {amount}"}), 400 | |
| conn.execute("UPDATE balances SET balance = balance - ? WHERE address = ?", (amount, addr)) | |
| # Reverse deferred revenue only for purchased tokens | |
| if tx["reason"].startswith("stripe_purchase"): | |
| conn.execute( | |
| """UPDATE deferred_revenue SET | |
| tokens_purchased = MAX(0, tokens_purchased - ?), | |
| deferred_cents = MAX(0, deferred_cents - (SELECT deferred_cents FROM deferred_revenue WHERE address = ?) / NULLIF(tokens_purchased, 0) * ?), | |
| last_updated = ? WHERE address = ? AND tokens_purchased > 0""", | |
| (amount, addr, amount, now, addr), | |
| ) | |
| elif tx_type == "debit": | |
| # Was a debit β credit back | |
| conn.execute( | |
| "INSERT OR REPLACE INTO balances (address, balance) VALUES (?, COALESCE((SELECT balance FROM balances WHERE address = ?), 0) + ?)", | |
| (addr, addr, amount), | |
| ) | |
| # Restore deferred revenue liability | |
| if tx["reason"].startswith("token_") or tx["reason"].startswith("shell_") or tx["reason"].startswith("kernel_") or tx["reason"].startswith("notebook_") or tx["reason"].startswith("deploy_") or tx["reason"].startswith("agent_"): | |
| conn.execute( | |
| """UPDATE deferred_revenue SET | |
| tokens_spent = MAX(0, tokens_spent - ?), | |
| deferred_cents = deferred_cents + (SELECT deferred_cents FROM deferred_revenue WHERE address = ?) / NULLIF(tokens_purchased, 0) * ?, | |
| last_updated = ? WHERE address = ? AND tokens_purchased > 0""", | |
| (amount, addr, amount, now, addr), | |
| ) | |
| # Mark original as rolled back | |
| rollback_tx_id = f"rollback_{tx_id}_{uuid.uuid4().hex[:8]}" | |
| conn.execute( | |
| "INSERT INTO transactions (tx_id, address, amount, type, reason, created_at, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)", | |
| (rollback_tx_id, addr, amount, "rollback", reason, now, json.dumps({"original_tx_id": tx_id, "original_type": tx_type})), | |
| ) | |
| # Reverse revenue if linked | |
| rev = conn.execute("SELECT revenue_id FROM revenue WHERE session_id = ?", (tx_id,)).fetchone() | |
| if rev: | |
| conn.execute("DELETE FROM revenue WHERE revenue_id = ?", (rev["revenue_id"],)) | |
| conn.commit() | |
| add_memory( | |
| title=f"Rollback: {tx_id}", | |
| content=f"Rolled back transaction {tx_id} for wallet {addr}. Reason: {reason}", | |
| source="finance-rollback", | |
| tags=["rollback", "finance"], | |
| metadata={"original_tx_id": tx_id, "wallet": addr, "amount": amount, "reason": reason}, | |
| importance=0.9, | |
| ) | |
| return jsonify({"rollback_tx_id": rollback_tx_id, "original_tx_id": tx_id, "wallet": addr, "amount": amount, "reason": reason}) | |
| # ββ Pixelator / GlyphIndex API ββββββββββββββββββββββββββββββββ | |
| def pixelator_ingest(): | |
| """Ingest HTML, tokenize to glyph units, emit proof receipt.""" | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"pixelator_ingest:{request.remote_addr}", window=60, max_requests=5): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| html = str(data.get("html", "")) | |
| url = str(data.get("url", "")).strip() or "about:blank" | |
| website_id = str(data.get("website_id", "")).strip() or f"site_{uuid.uuid4().hex[:8]}" | |
| title = str(data.get("title", "")).strip() | |
| wallet = str(data.get("wallet", "")).strip() | |
| if not html: | |
| return jsonify({"error": "html required"}), 400 | |
| # Cap HTML size to prevent abuse (C30) | |
| if len(html) > 2_000_000: | |
| return jsonify({"error": "HTML too large. Max 2MB."}), 413 | |
| # Debit tokens | |
| if wallet: | |
| addr = _normalize_wallet(wallet) | |
| bal = get_balance(addr) | |
| cost = _get_token_cost("pixelator_ingest") | |
| if bal < cost: | |
| return jsonify({"error": f"Insufficient tokens. Need {cost}, have {bal}."}), 402 | |
| debit_tokens(addr, cost, "pixelator_ingest", {"url": url, "website_id": website_id}) | |
| try: | |
| result = MembraPixelator.ingest(html, url, website_id, title) | |
| receipt = create_receipt( | |
| kind="pixelator-ingest", | |
| title=f"Pixelated: {result['title'] or url}", | |
| status="completed", | |
| command=f"pixelator_ingest:{result['page_id']}", | |
| metadata=result, | |
| ) | |
| result["receipt_id"] = receipt["receipt_id"] | |
| result["tokens_debited"] = _get_token_cost("pixelator_ingest") if wallet else 0 | |
| return jsonify(result), 201 | |
| except Exception as e: | |
| logger.exception("Pixelator ingest failed") | |
| return jsonify({"error": "Pixelator ingest failed. Check logs."}), 500 | |
| def pixelator_page_glyphs(page_id: str): | |
| """Get glyph units for a page.""" | |
| if not _rate_check(f"pixelator_glyphs:{request.remote_addr}", window=60, max_requests=20): | |
| return rate_limit_response() | |
| limit = max(1, min(int(request.args.get("limit", 1000)), 5000)) | |
| offset = max(0, int(request.args.get("offset", 0))) | |
| try: | |
| glyphs = MembraPixelator.get_page_glyphs(page_id, limit, offset) | |
| return jsonify({ | |
| "page_id": page_id, | |
| "glyphs": glyphs, | |
| "count": len(glyphs), | |
| "limit": limit, | |
| "offset": offset, | |
| }) | |
| except Exception as e: | |
| logger.exception("Pixelator glyphs fetch failed") | |
| return jsonify({"error": str(e)}), 500 | |
| def pixelator_page_activation(page_id: str): | |
| """Get page activation summary with glyph statistics.""" | |
| if not _rate_check(f"pixelator_activation:{request.remote_addr}", window=60, max_requests=30): | |
| return rate_limit_response() | |
| try: | |
| result = MembraPixelator.get_page_activation(page_id) | |
| return jsonify(result) | |
| except ValueError as e: | |
| return jsonify({"error": str(e)}), 404 | |
| except Exception as e: | |
| logger.exception("Pixelator activation fetch failed") | |
| return jsonify({"error": str(e)}), 500 | |
| def pixelator_top_glyphs(website_id: str): | |
| """Get highest-value glyphs across a website.""" | |
| if not _rate_check(f"pixelator_top:{request.remote_addr}", window=60, max_requests=20): | |
| return rate_limit_response() | |
| limit = max(1, min(int(request.args.get("limit", 50)), 200)) | |
| try: | |
| glyphs = MembraPixelator.get_top_glyphs(website_id, limit) | |
| return jsonify({ | |
| "website_id": website_id, | |
| "glyphs": glyphs, | |
| "count": len(glyphs), | |
| }) | |
| except Exception as e: | |
| logger.exception("Pixelator top glyphs fetch failed") | |
| return jsonify({"error": str(e)}), 500 | |
| def pixelator_learn(): | |
| """Retrain DOM weights and semantic lexicon from actual page results. | |
| Higher page_activation β reinforce tag weights and term confidence.""" | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"pixelator_learn:{request.remote_addr}", window=60, max_requests=5): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| min_samples = max(1, int(data.get("min_samples", 3))) | |
| now = datetime.now(timezone.utc).isoformat() | |
| with _db() as conn: | |
| # Learn DOM weights: update each tag's weight toward the average page_activation of pages using that tag | |
| tag_rows = conn.execute(""" | |
| SELECT tag, COUNT(*) AS n, AVG(page_activation_value) AS avg_pa | |
| FROM pages p | |
| JOIN ( | |
| SELECT DISTINCT page_id, SUBSTR(dom_path, INSTR(dom_path, '>') + 2) AS tag | |
| FROM glyph_units | |
| ) g ON p.page_id = g.page_id | |
| GROUP BY tag HAVING n >= ? | |
| """, (min_samples,)).fetchall() | |
| dom_updated = 0 | |
| for row in tag_rows: | |
| tag, n, avg_pa = row["tag"], row["n"], row["avg_pa"] or 0.0 | |
| # New weight = (old_weight * old_samples + avg_pa) / (old_samples + 1) | |
| old = conn.execute("SELECT weight, sample_count FROM dom_weights WHERE tag = ?", (tag,)).fetchone() | |
| if old: | |
| new_weight = (old["weight"] * old["sample_count"] + avg_pa) / (old["sample_count"] + n) | |
| new_count = old["sample_count"] + n | |
| else: | |
| new_weight = avg_pa | |
| new_count = n | |
| conn.execute( | |
| """INSERT OR REPLACE INTO dom_weights (tag, weight, sample_count, avg_page_activation, updated_at) | |
| VALUES (?, ?, ?, ?, ?)""", | |
| (tag, round(new_weight, 4), new_count, round(avg_pa, 4), now), | |
| ) | |
| dom_updated += 1 | |
| # Learn semantic lexicon: reinforce terms that appear on high-activation pages | |
| term_rows = conn.execute(""" | |
| SELECT char_value AS term, semantic_role AS category, COUNT(*) AS freq, | |
| AVG(glyph_value) AS avg_gv, AVG(page_activation_value) AS avg_pa | |
| FROM glyph_units g | |
| JOIN pages p ON g.page_id = p.page_id | |
| WHERE semantic_role IN ('entity','action','commercial','legal') | |
| GROUP BY term, category HAVING freq >= ? | |
| """, (min_samples,)).fetchall() | |
| lex_updated = 0 | |
| for row in term_rows: | |
| term, category, freq, avg_gv, avg_pa = row["term"], row["category"], row["freq"], row["avg_gv"], row["avg_pa"] | |
| # Confidence proportional to average glyph value and page activation | |
| confidence = min(0.99, (avg_gv or 0.0) * 0.1 + (avg_pa or 0.0) * 0.01) | |
| old = conn.execute( | |
| "SELECT frequency, confidence FROM semantic_lexicon WHERE term = ? AND category = ?", | |
| (term, category), | |
| ).fetchone() | |
| if old: | |
| freq = old["frequency"] + freq | |
| confidence = (old["confidence"] + confidence) / 2 | |
| conn.execute( | |
| """INSERT OR REPLACE INTO semantic_lexicon | |
| (term, category, frequency, confidence, source_count, updated_at) | |
| VALUES (?, ?, ?, ?, ?, ?)""", | |
| (term, category, freq, round(confidence, 4), freq, now), | |
| ) | |
| lex_updated += 1 | |
| conn.commit() | |
| return jsonify({ | |
| "dom_weights_updated": dom_updated, | |
| "lexicon_terms_updated": lex_updated, | |
| "min_samples": min_samples, | |
| "learned_at": now, | |
| }) | |
| def manage_costs(): | |
| """Get or update token costs. No hardcoded values β DB is source of truth.""" | |
| if request.method == "GET": | |
| with _db() as conn: | |
| rows = conn.execute("SELECT operation, cost, source, updated_at FROM token_costs ORDER BY operation").fetchall() | |
| return jsonify({"costs": [dict(r) for r in rows]}) | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| data = request.json or {} | |
| operation = str(data.get("operation", "")).strip() | |
| cost = data.get("cost") | |
| if not operation or cost is None: | |
| return jsonify({"error": "operation and cost required"}), 400 | |
| try: | |
| cost = int(cost) | |
| except (TypeError, ValueError): | |
| return jsonify({"error": "cost must be an integer"}), 400 | |
| if cost < 0: | |
| return jsonify({"error": "cost must be non-negative"}), 400 | |
| now = datetime.now(timezone.utc).isoformat() | |
| with _db() as conn: | |
| conn.execute( | |
| "INSERT OR REPLACE INTO token_costs (operation, cost, source, updated_at) VALUES (?, ?, 'admin', ?)", | |
| (operation, cost, now), | |
| ) | |
| conn.commit() | |
| return jsonify({"operation": operation, "cost": cost, "updated_at": now}), 200 | |
| # ββ GA-RL Crawler API βββββββββββββββββββββββββββββββββββββββββ | |
| def crawler_targets(): | |
| """List or register crawl target websites.""" | |
| if request.method == "GET": | |
| if not _rate_check(f"crawler_targets:{request.remote_addr}", window=60, max_requests=30): | |
| return rate_limit_response() | |
| with _db() as conn: | |
| rows = conn.execute("SELECT * FROM crawl_targets ORDER BY fitness_score DESC").fetchall() | |
| return jsonify({"targets": [dict(r) for r in rows], "count": len(rows)}) | |
| # POST: register new target | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| data = request.json or {} | |
| website_id = str(data.get("website_id", "")).strip() | |
| root_url = str(data.get("root_url", "")).strip() | |
| if not website_id or not root_url: | |
| return jsonify({"error": "website_id and root_url required"}), 400 | |
| try: | |
| crawler = GARLCrawler() | |
| result = crawler.add_target( | |
| website_id=website_id, | |
| root_url=root_url, | |
| name=str(data.get("name", "")).strip(), | |
| depth=max(1, min(int(data.get("crawl_depth", 2)), 5)), | |
| priority=float(data.get("priority", 1.0)), | |
| selector_rules=str(data.get("selector_rules", "")), | |
| ) | |
| return jsonify(result), 201 | |
| except ValueError as e: | |
| return jsonify({"error": str(e)}), 409 | |
| except Exception as e: | |
| logger.exception("Crawler add_target failed") | |
| return jsonify({"error": "Failed to add target"}), 500 | |
| def crawler_target_delete(target_id: str): | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| with _db() as conn: | |
| conn.execute("DELETE FROM crawl_targets WHERE target_id = ?", (target_id,)) | |
| conn.commit() | |
| return jsonify({"deleted": target_id}) | |
| def crawler_enqueue(): | |
| """Add a URL to the rotator buffer crawl queue.""" | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"crawler_queue:{request.remote_addr}", window=60, max_requests=10): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| target_id = str(data.get("target_id", "")).strip() | |
| url = str(data.get("url", "")).strip() | |
| if not target_id or not url: | |
| return jsonify({"error": "target_id and url required"}), 400 | |
| depth = max(0, min(int(data.get("depth", 0)), 5)) | |
| priority_score = float(data.get("priority_score", 0.0)) | |
| try: | |
| crawler = GARLCrawler() | |
| result = crawler.enqueue(target_id, url, depth, priority_score) | |
| return jsonify(result), 201 | |
| except Exception as e: | |
| logger.exception("Crawler enqueue failed") | |
| return jsonify({"error": str(e)}), 500 | |
| def crawler_queue_list(): | |
| if not _rate_check(f"crawler_queue_list:{request.remote_addr}", window=60, max_requests=30): | |
| return rate_limit_response() | |
| limit = max(1, min(int(request.args.get("limit", 100)), 500)) | |
| with _db() as conn: | |
| rows = conn.execute("SELECT * FROM crawl_queue ORDER BY added_at DESC LIMIT ?", (limit,)).fetchall() | |
| return jsonify({"queue": [dict(r) for r in rows], "count": len(rows)}) | |
| def crawler_ingest(): | |
| """Run one crawl step: select next URL via RL, fetch, pixelate, reward.""" | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"crawler_ingest:{request.remote_addr}", window=60, max_requests=5): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| wallet = str(data.get("wallet", "")).strip() | |
| crawler = GARLCrawler() | |
| next_item = crawler.select_next() | |
| if not next_item: | |
| return jsonify({"status": "idle", "message": "No pending items in queue"}) | |
| queue_id = next_item["queue_id"] | |
| target_id = next_item["target_id"] | |
| url = next_item["url"] | |
| try: | |
| result = crawler.ingest_url(url, target_id, queue_id, wallet) | |
| return jsonify(result) | |
| except Exception as e: | |
| logger.exception("Crawler ingest failed") | |
| return jsonify({"error": str(e)}), 500 | |
| def crawler_results(): | |
| if not _rate_check(f"crawler_results:{request.remote_addr}", window=60, max_requests=30): | |
| return rate_limit_response() | |
| website_id = request.args.get("website_id", "").strip() or None | |
| limit = max(1, min(int(request.args.get("limit", 100)), 500)) | |
| crawler = GARLCrawler() | |
| results = crawler.get_results(website_id, limit) | |
| return jsonify({"results": results, "count": len(results)}) | |
| def crawler_evolve(): | |
| """Run one GA generation on the target population.""" | |
| auth = require_auth() | |
| if auth: | |
| return auth | |
| if not _rate_check(f"crawler_evolve:{request.remote_addr}", window=60, max_requests=5): | |
| return rate_limit_response() | |
| try: | |
| crawler = GARLCrawler() | |
| result = crawler.run_evolution() | |
| return jsonify(result) | |
| except Exception as e: | |
| logger.exception("Crawler evolution failed") | |
| return jsonify({"error": str(e)}), 500 | |
| def crawler_policy(): | |
| if not _rate_check(f"crawler_policy:{request.remote_addr}", window=60, max_requests=30): | |
| return rate_limit_response() | |
| crawler = GARLCrawler() | |
| policy = crawler.get_policy() | |
| return jsonify({"policy": policy, "count": len(policy)}) | |
| # ββ ETHR Oracle βββββββββββββββββββββββββββββββββββββββββββββββ | |
| ETHR_ADMIN_KEY = os.environ.get("ETHR_ADMIN_KEY", "") | |
| def ethr_proof_index(): | |
| """Compute ETHR proof index from live CLAIMOS metrics.""" | |
| if not _rate_check(f"ethr:{request.remote_addr}", window=60, max_requests=30): | |
| return rate_limit_response() | |
| with _db() as conn: | |
| # Proof metrics | |
| verified_receipts = conn.execute( | |
| "SELECT COUNT(*) AS c FROM receipts WHERE kind LIKE 'claim-%' AND status = 'completed'" | |
| ).fetchone()["c"] | |
| reviewed_packets = conn.execute( | |
| "SELECT COUNT(*) AS c FROM evidence WHERE evidence_strength > 0" | |
| ).fetchone()["c"] | |
| resolved_contradictions = conn.execute( | |
| "SELECT COUNT(*) AS c FROM contradictions WHERE resolved = 1" | |
| ).fetchone()["c"] | |
| # Risk metrics | |
| disputes = conn.execute( | |
| "SELECT COUNT(*) AS c FROM contradictions WHERE resolved = 0" | |
| ).fetchone()["c"] | |
| invalid_evidence = conn.execute( | |
| "SELECT COUNT(*) AS c FROM evidence WHERE evidence_strength < 0.3" | |
| ).fetchone()["c"] | |
| procedural_failures = conn.execute( | |
| "SELECT COUNT(*) AS c FROM claims WHERE status IN ('unreviewed','closed')" | |
| ).fetchone()["c"] | |
| # Aggregate claim state | |
| claim_stats = conn.execute( | |
| "SELECT AVG(p_recovery) AS avg_p, AVG(liquidity_score) AS avg_liq, AVG(contradiction_density) AS avg_cx FROM claims" | |
| ).fetchone() | |
| delta_proof = verified_receipts + reviewed_packets + resolved_contradictions | |
| delta_risk = disputes + invalid_evidence + procedural_failures | |
| net_change = delta_proof - delta_risk | |
| # Normalize to small increments | |
| normalized = net_change / max(1, delta_proof + delta_risk) | |
| return jsonify({ | |
| "token": "ETHR", | |
| "description": "Elastic proof-index token for Membra verification capacity", | |
| "delta": { | |
| "verified_receipts": verified_receipts, | |
| "reviewed_packets": reviewed_packets, | |
| "resolved_contradictions": resolved_contradictions, | |
| "disputes": disputes, | |
| "invalid_evidence": invalid_evidence, | |
| "procedural_failures": procedural_failures, | |
| }, | |
| "net_change": round(normalized, 8), | |
| "claim_stats": { | |
| "avg_p_recovery": round(claim_stats["avg_p"] or 0, 4), | |
| "avg_liquidity": round(claim_stats["avg_liq"] or 0, 4), | |
| "avg_contradiction_density": round(claim_stats["avg_cx"] or 0, 4), | |
| }, | |
| "updated_at": datetime.now(timezone.utc).isoformat(), | |
| }) | |
| def ethr_update_multiplier(): | |
| """Oracle endpoint to update ETHR multiplier. Requires ETHR_ADMIN_KEY.""" | |
| if not _rate_check(f"ethr_admin:{request.remote_addr}", window=60, max_requests=10): | |
| return rate_limit_response() | |
| data = request.json or {} | |
| auth_key = str(data.get("admin_key", "")).strip() | |
| if not ETHR_ADMIN_KEY or auth_key != ETHR_ADMIN_KEY: | |
| return jsonify({"error": "Unauthorized"}), 401 | |
| multiplier = float(data.get("multiplier", 1.0)) | |
| if multiplier <= 0: | |
| return jsonify({"error": "Multiplier must be > 0"}), 400 | |
| now = datetime.now(timezone.utc).isoformat() | |
| return jsonify({ | |
| "token": "ETHR", | |
| "multiplier": multiplier, | |
| "status": "updated", | |
| "updated_at": now, | |
| }) | |
| # ββ Main ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| if __name__ == "__main__": | |
| load_config() | |
| load_settings() | |
| load_memory() | |
| load_apps() | |
| load_receipts() | |
| _init_token_db() | |
| save_state() | |
| if not TERMINAL_AGENT_TOKEN: | |
| logger.warning("TERMINAL_AGENT_TOKEN is not set; command routes will reject all requests.") | |
| logger.info(f"Starting Terminal Agent on port {PORT}") | |
| app.run(host="0.0.0.0", port=PORT, threaded=True) | |