Spaces:
Sleeping
Sleeping
| """Matrix Context — frontend / control-plane server. | |
| A self-contained, Hugging-Face-deployable launcher that serves: | |
| * the static control-plane UI in ``frontend/app/`` (Overview, Inspector, | |
| Builder, Memory, Experts, Routing, Benchmarks, Standard, Settings), and | |
| * the live MoC Contract v1 API under ``/v1`` — by reusing the published | |
| backend's ``RestService`` / ``dispatch``. | |
| This is **additive and non-destructive**: it imports ``matrix_context`` and the | |
| existing REST app; it does not modify them. A small demo memory set is seeded on | |
| startup so the Space is useful immediately. | |
| python frontend/server.py # local -> http://127.0.0.1:7860 | |
| PORT=7860 HOST=0.0.0.0 python ... # container / Hugging Face Space | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import os | |
| from http.server import BaseHTTPRequestHandler, HTTPServer | |
| from pathlib import Path | |
| from urllib.parse import parse_qs, urlparse | |
| from matrix_context import ContextManager | |
| from matrix_context.serve.rest.app import RestService, dispatch | |
| APP_DIR = Path(__file__).parent / "app" | |
| HOST = os.environ.get("HOST", "127.0.0.1") | |
| PORT = int(os.environ.get("PORT", "7860")) | |
| DB_PATH = os.environ.get("MATRIX_CONTEXT_PATH", ":memory:") | |
| _CONTENT_TYPES = {".html": "text/html; charset=utf-8", | |
| ".js": "application/javascript; charset=utf-8", | |
| ".css": "text/css; charset=utf-8", | |
| ".svg": "image/svg+xml", ".json": "application/json", | |
| ".png": "image/png", ".ico": "image/x-icon"} | |
| # Demo seed — a small, typed, multi-scope memory set so every view is populated. | |
| SEED = [ | |
| ("Decision: use SQLite as the default storage backend; vectors accelerate, SQL is the source of truth.", | |
| "semantic", "project:matrix-context", 0.95, ["backend", "sqlite", "type:decision"]), | |
| ("Matrix Context exposes both a Python SDK and an MCP server so agents and operators share one memory plane.", | |
| "semantic", "project:matrix-context", 0.9, ["mcp", "sdk", "type:decision"]), | |
| ("Policy: the agent must never store API keys, tokens, or PII in durable memory.", | |
| "policy", "project:matrix-context", 0.95, ["security", "pii", "type:rule"]), | |
| ("Decision: defer Milvus support to v2; pgvector lands in v1.", | |
| "episodic", "project:matrix-context", 0.8, ["milvus", "roadmap", "type:decision"]), | |
| ("The user prefers local-first tools over cloud services by default.", | |
| "profile", "user:42", 0.9, ["preference", "type:preference"]), | |
| ("The user prefers concise, direct answers with code first.", | |
| "profile", "user:42", 0.8, ["preference", "tone", "type:preference"]), | |
| ("The whitepaper reports that routed typed context cuts distractors at equal recall.", | |
| "document", "project:matrix-context", 0.7, ["whitepaper", "type:document"]), | |
| ("Decision: ship the REST API and Context Console before the MCP server.", | |
| "semantic", "project:acme", 0.85, ["rest", "console", "type:decision"]), | |
| ("Policy in project:acme — audit-log every write to profile or policy memory.", | |
| "policy", "project:acme", 0.88, ["audit", "governance", "type:rule"]), | |
| ("In the last session we agreed the demo should run on Hugging Face Spaces.", | |
| "episodic", "project:acme", 0.65, ["session", "demo", "type:episode"]), | |
| ] | |
| def build_service() -> RestService: | |
| mgr = ContextManager.create("matrix-context-demo", path=DB_PATH) | |
| if not mgr.store.all_items(): | |
| for content, expert, scope, importance, tags in SEED: | |
| mgr.remember(content, expert=expert, scope=scope, | |
| importance=importance, tags=tags) | |
| return RestService(mgr) | |
| def _static(path: str): | |
| """Resolve a static asset under APP_DIR (path-traversal safe).""" | |
| rel = path.lstrip("/") or "index.html" | |
| target = (APP_DIR / rel).resolve() | |
| if APP_DIR.resolve() not in target.parents and target != APP_DIR.resolve(): | |
| return None | |
| if not target.is_file(): | |
| return None | |
| ctype = _CONTENT_TYPES.get(target.suffix, "application/octet-stream") | |
| return target.read_bytes(), ctype | |
| def make_handler(service: RestService): | |
| class Handler(BaseHTTPRequestHandler): | |
| def log_message(self, *a): | |
| pass | |
| def _send_json(self, status, payload): | |
| data = json.dumps(payload).encode() | |
| self.send_response(status) | |
| self.send_header("Content-Type", "application/json") | |
| self.send_header("Content-Length", str(len(data))) | |
| self.end_headers() | |
| self.wfile.write(data) | |
| def _send_bytes(self, data, ctype, status=200): | |
| self.send_response(status) | |
| self.send_header("Content-Type", ctype) | |
| self.send_header("Content-Length", str(len(data))) | |
| self.end_headers() | |
| self.wfile.write(data) | |
| def _read_body(self): | |
| n = int(self.headers.get("Content-Length") or 0) | |
| if not n: | |
| return {} | |
| try: | |
| obj = json.loads(self.rfile.read(n) or b"{}") | |
| return obj if isinstance(obj, dict) else {} | |
| except json.JSONDecodeError: | |
| return {} | |
| def do_GET(self): | |
| p = urlparse(self.path) | |
| if p.path.startswith("/v1"): | |
| st, payload = dispatch(service, "GET", p.path, query=parse_qs(p.query)) | |
| self._send_json(st, payload) | |
| return | |
| asset = _static("index.html" if p.path == "/" else p.path) | |
| if asset: | |
| self._send_bytes(*asset) | |
| else: | |
| self._send_json(404, {"error": f"not found: {p.path}"}) | |
| def do_POST(self): | |
| p = urlparse(self.path) | |
| if p.path.startswith("/v1"): | |
| st, payload = dispatch(service, "POST", p.path, body=self._read_body()) | |
| self._send_json(st, payload) | |
| else: | |
| self._send_json(404, {"error": f"not found: {p.path}"}) | |
| return Handler | |
| def main() -> int: | |
| service = build_service() | |
| httpd = HTTPServer((HOST, PORT), make_handler(service)) | |
| n = len(service.m.store.all_items()) | |
| print(f"Matrix Context control plane on http://{HOST}:{PORT} ({n} seeded items)") | |
| try: | |
| httpd.serve_forever() | |
| except KeyboardInterrupt: | |
| httpd.server_close() | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |