Spaces:
Sleeping
Sleeping
File size: 26,983 Bytes
ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 7927b9d ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 7927b9d f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 7927b9d 67bc053 7927b9d ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 f32e8dc ce45eb0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | /* Matrix Context — control plane (admin UI). Zero-dependency SPA wired to /v1.
* Views: Overview, Inspector, Builder, Memory, Experts, Routing, Benchmarks,
* Standard, Settings. Enterprise basics: top-bar scope selector (tenant
* isolation), auth token, graceful offline state. (Cloud omitted — pre-launch.)
*/
(function () {
"use strict";
const MC = window.MC;
const $ = (s, r) => (r || document).querySelector(s);
const el = (h) => { const t = document.createElement("template"); t.innerHTML = h.trim(); return t.content.firstChild; };
const esc = (s) => String(s == null ? "" : s).replace(/[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ }[c]));
const state = { tab: "overview", scope: "/", online: false, version: null, health: null, experts: [], scopes: [], items: [] };
const BENCH = {
note: "sentence-transformers/all-MiniLM-L6-v2 · test split · K=8",
rows: [
{ m: "bm25_rag", kw: 100, pa: 81, adv: 64, hd: 72 },
{ m: "dense_rag", kw: 83, pa: 79, adv: 74, hd: 103 },
{ m: "hybrid_rag", kw: 96, pa: 88, adv: 71, hd: 91 },
{ m: "moc_rag_e2", kw: 96, pa: 86, adv: 78, hd: 48 },
{ m: "moc_rag_e3", kw: 96, pa: 89, adv: 79, hd: 62 },
],
};
const ENDPOINTS = ["GET /v1/health", "GET /v1/version", "GET /v1/experts", "GET /v1/scopes",
"GET /v1/items", "GET /v1/items/{id}", "POST /v1/remember", "POST /v1/recall",
"POST /v1/pack", "POST /v1/inspect", "POST /v1/router/explain", "POST /v1/forget"];
const NAV = [
["Workspace", [["overview", "Overview", "◎"], ["inspector", "Inspector", "⌕"], ["builder", "Ingest", "↥"], ["memory", "Memory", "▤"]]],
["Develop", [["integrate", "Integrate", "⌁"]]],
["Engine", [["experts", "Experts", "❖"], ["routing", "Routing", "⇄"], ["benchmarks", "Benchmarks", "▦"]]],
["Platform", [["standard", "MoC Contract", "§"], ["settings", "Settings", "⚙"]]],
];
// ---- ingest classifier (Compatible Mode) ----
const SAMPLE = `# Project notes
## Decision: default backend
Use SQLite as the default storage backend; vectors accelerate, SQL is the source of truth.
## Policy: secrets
The agent must never store API keys, tokens, or PII in durable memory.
## Preference
The user prefers local-first tools over cloud services.
## Roadmap
Defer Milvus to v2; pgvector lands in v1.`;
const EXPERT_FOR_TYPE = { decision: "semantic", fact: "semantic", rule: "policy", preference: "profile", event: "episodic", document: "document" };
function classify(text) {
if (!text || !text.trim()) return [];
const blocks = text.split(/\n(?=#)|\n\s*\n/).map((b) => b.replace(/^#+\s*/, "").replace(/\s+/g, " ").trim()).filter((b) => b.length > 12);
return blocks.slice(0, 20).map((b, i) => {
const low = b.toLowerCase();
let type = "fact";
if (/\b(decide|decision|chose|default|will use|roadmap|defer|v1|v2|phase)\b/.test(low)) type = "decision";
else if (/\b(policy|must|never|forbidden|require)\b/.test(low)) type = "rule";
else if (/\b(prefer|preference|like)\b/.test(low)) type = "preference";
const has = (id) => state.experts.some((e) => e.id === id);
let expert = EXPERT_FOR_TYPE[type] || "semantic";
if (!has(expert)) expert = (state.experts[0] && state.experts[0].id) || "semantic";
const importance = Math.round(Math.min(0.98, 0.55 + (type === "rule" ? 0.4 : type === "decision" ? 0.32 : 0.18)) * 100) / 100;
const tags = Array.from(new Set((low.match(/\b(mcp|sdk|api|sqlite|milvus|pgvector|policy|secrets|local-first|memory|scope|roadmap)\b/g) || []))).slice(0, 4);
return { id: "c" + i, content: b.slice(0, 280), type, expert, importance, confidence: Math.round((0.75 + Math.random() * 0.2) * 100) / 100, tags: tags.length ? tags : ["context"], approved: true };
});
}
// ---- boot / chrome ----
async function boot() {
try { state.health = await MC.health(); state.version = await MC.version(); state.online = true; }
catch (e) { state.online = false; }
if (state.online) {
try { state.experts = await MC.experts(); } catch (e) {}
try { state.scopes = await MC.scopes(); } catch (e) {}
try { state.items = (await MC.items()).items; } catch (e) {}
}
chrome(); render();
}
async function refreshStore() { try { state.items = (await MC.items()).items; state.health = await MC.health(); chrome(); } catch (e) {} }
function chrome() {
const p = $("#health"); if (p) { p.className = "pill " + (state.online ? "ok" : "bad"); p.textContent = state.online ? "● online" : "● offline"; }
const ver = $("#ver"); if (ver) ver.textContent = state.version ? ("contract " + state.version.contract) : "—";
const b = $("#banner"); if (b) b.classList.toggle("show", !state.online);
const sel = $("#scopesel");
if (sel) {
sel.innerHTML = `<option value="/">All scopes</option>` + state.scopes.map((s) => `<option value="${esc(s.id)}" ${s.id === state.scope ? "selected" : ""}>${esc(s.label)}</option>`).join("");
sel.value = state.scope;
}
}
function counts(field) { const m = {}; state.items.forEach((it) => { m[it[field]] = (m[it[field]] || 0) + 1; }); return m; }
const scopeLabel = () => (state.scope === "/" ? "all scopes" : state.scope);
function offline(v) { v.appendChild(el(`<div class="card"><h2>Disconnected</h2><p class="muted">The backend is not reachable. Start it (<span class="mono">python frontend/server.py</span>) or check Settings, then reload.</p></div>`)); }
function render() {
document.querySelectorAll(".tab").forEach((t) => t.classList.toggle("active", t.dataset.tab === state.tab));
const v = $("#view"); v.innerHTML = "";
const views = { overview: vOverview, inspector: vInspector, builder: vBuilder, memory: vMemory, integrate: vIntegrate, experts: vExperts, routing: vRouting, benchmarks: vBench, standard: vStandard, settings: vSettings };
if (!state.online && ["overview", "inspector", "builder", "memory", "experts", "routing"].indexOf(state.tab) >= 0) {
v.appendChild(el(`<div><h1>${esc(state.tab[0].toUpperCase() + state.tab.slice(1))}</h1></div>`)); offline(v); return;
}
(views[state.tab] || vOverview)(v);
}
// ---- Overview ----
function vOverview(v) {
const ec = counts("expert"), sc = counts("scope");
v.appendChild(el(`<div>
<h1>Control plane</h1>
<p class="sub">Inspectable, typed memory for AI agents — routed retrieval, budgeted packs, every choice explained. Backed by MoC Contract v1.</p>
<div class="grid cols-3">
<div class="card"><div class="lbl">Memory items</div><div class="stat acc">${state.health ? state.health.items : "—"}</div></div>
<div class="card"><div class="lbl">Context experts</div><div class="stat">${state.experts.length}</div></div>
<div class="card"><div class="lbl">Scopes</div><div class="stat">${state.scopes.length}</div></div>
</div>
<div class="grid cols-3" style="margin-top:14px">
<div class="card value-card"><h3>Route, don't dump</h3><p>Each query goes to the few typed experts it needs — not one flat index.</p></div>
<div class="card value-card"><h3>Budgeted packs</h3><p>Relevance · importance · recency − redundancy, under a token budget.</p></div>
<div class="card value-card"><h3>Always inspectable</h3><p>See selected/dropped experts, scores, and reasons for every item.</p></div>
</div>
<div class="grid cols-2" style="margin-top:14px">
<div class="card"><h2>Experts</h2>${state.experts.map((e) => `<div class="kv"><span>${esc(e.name)}</span><span class="mono dim">${ec[e.id] || 0}</span></div>`).join("") || '<div class="dim">none</div>'}</div>
<div class="card"><h2>Scopes</h2>${state.scopes.map((s) => `<div class="kv"><span class="mono">${esc(s.label)}</span><span class="mono dim">${sc[s.id] || 0}</span></div>`).join("") || '<div class="dim">none</div>'}</div>
</div>
<div class="card" style="margin-top:14px"><h2>Get started</h2>
<div class="install">pip install matrix-context · matrix-context serve --transport rest</div>
<div class="kv" style="margin-top:10px"><span class="muted">Conformance</span><span class="mono acc">${state.online ? "MoC API v1 Compatible" : "—"}</span></div>
</div>
</div>`));
}
// ---- Inspector ----
function vInspector(v) {
v.appendChild(el(`<div>
<h1>Inspector</h1>
<p class="sub">Ask a question; see exactly why each item was routed, kept, or dropped. <span class="chip on">scope: ${esc(scopeLabel())}</span></p>
<div class="grid cols-inspect">
<div class="card"><h2>Query</h2>
<label>Question</label><input id="q" value="what did we decide about the backend?"/>
<div class="row" style="margin-top:10px"><div style="flex:1"><label>Max tokens</label><input id="mt" type="number" value="120"/></div><div style="flex:1"><label>Top experts</label><input id="te" type="number" value="3"/></div></div>
<div class="row" style="margin-top:12px"><button id="run">Inspect</button></div>
</div>
<div class="card" id="packCard"><h2>Context pack</h2><div id="pack" class="dim">…</div></div>
<div class="card" id="routeCard"><h2>Router</h2><div id="route" class="dim">…</div></div>
</div>
</div>`));
const run = async () => {
$("#pack").innerHTML = '<div class="dim">running…</div>'; $("#route").innerHTML = "";
let r; try { r = await MC.inspect($("#q").value, { scope: state.scope, max_tokens: +$("#mt").value, top_experts: +$("#te").value }); }
catch (e) { $("#pack").innerHTML = `<div class="reason">${esc(e.message)}</div>`; return; }
const max = Math.max.apply(null, r.routing.scores.map((s) => s.score).concat([0.0001]));
$("#routeCard").querySelector("h2").innerHTML = `Router <span class="dim" style="text-transform:none">— ${esc(r.routing.reason)}</span>`;
$("#route").innerHTML = `<div style="margin-bottom:10px">${r.routing.selected.map((e) => `<span class="chip on">${esc(e)}</span>`).join("")}${r.routing.unselected.map((e) => `<span class="chip">${esc(e)}</span>`).join("")}</div>` +
`<table><tbody>${r.routing.scores.map((s) => { const on = r.routing.selected.indexOf(s.expert) >= 0; return `<tr><td>${on ? "● " : ""}${esc(s.expert)}</td><td class="mono">${s.score.toFixed(3)}</td><td><div class="bar"><span style="width:${(100 * s.score / max).toFixed(0)}%;${on ? "" : "background:#2c5b46"}"></span></div></td></tr>`; }).join("")}</tbody></table>`;
$("#packCard").querySelector("h2").innerHTML = `Context pack <span class="pill">${r.pack.tokens}/${r.pack.maxTokens} tok</span>`;
$("#pack").innerHTML = `<table><thead><tr><th>Expert</th><th>Content</th><th>Score</th></tr></thead><tbody>${r.pack.items.map((p) => `<tr><td><span class="chip on">${esc(p.expert)}</span></td><td>${esc(p.content)}<div class="mono dim" style="font-size:11px">rel ${p.breakdown.relevance} · imp ${p.breakdown.importance} · rec ${p.breakdown.recency} · −red ${p.breakdown.redundancy}</div></td><td class="mono">${p.final_score}</td></tr>`).join("")}</tbody>${r.pack.dropped.length ? `<tbody>${r.pack.dropped.map((d) => `<tr class="dropped"><td><span class="chip">${esc(d.expert)}</span></td><td class="mono">${esc(d.id)}</td><td class="reason">dropped</td></tr>`).join("")}</tbody>` : ""}</table><h2 style="margin-top:14px">Prompt-ready pack</h2><pre>${esc(r.pack.prompt)}</pre>`;
};
$("#run", v).onclick = run; run();
}
// ---- Builder ----
let cands = [];
function vBuilder(v) {
const defScope = state.scope !== "/" ? state.scope : ((state.scopes[0] && state.scopes[0].id) || "project:demo");
v.appendChild(el(`<div>
<h1>Ingest</h1>
<p class="sub">Never ingest blindly — paste, review typed candidates, approve, commit, then prove recall. <span class="tag">Compatible Mode: client-side chunk → POST /v1/remember</span></p>
<div class="card"><label>Source text</label><textarea id="src" placeholder="Paste documents, decisions, notes…"></textarea>
<div class="row" style="margin-top:10px"><div style="flex:0 1 280px"><label>Scope</label><input id="bscope" value="${esc(defScope)}"/></div><button id="sample" class="ghost">Load sample</button><button id="analyze">Analyze →</button></div>
</div><div id="cands"></div><div id="commit"></div>
</div>`));
$("#sample", v).onclick = () => { $("#src").value = SAMPLE; };
$("#analyze", v).onclick = () => { cands = classify($("#src").value); paint(); };
function paint() {
const host = $("#cands"); host.innerHTML = ""; if (!cands.length) return;
const ap = cands.filter((c) => c.approved).length;
host.appendChild(el(`<div class="card" style="margin-top:14px"><h2>Review — ${ap}/${cands.length} approved</h2>
<table><thead><tr><th>✓</th><th>Type</th><th>Content</th><th>Expert</th><th>Imp.</th></tr></thead><tbody>${cands.map((c, i) => `<tr><td><input type="checkbox" data-i="${i}" ${c.approved ? "checked" : ""} style="width:auto"/></td><td><span class="chip">${esc(c.type)}</span></td><td>${esc(c.content)}</td><td><select data-e="${i}">${state.experts.map((e) => `<option value="${esc(e.id)}" ${e.id === c.expert ? "selected" : ""}>${esc(e.name)}</option>`).join("")}</select></td><td class="mono">${c.importance}</td></tr>`).join("")}</tbody></table>
<div class="row" style="margin-top:12px"><button id="go">Commit ${ap} → POST /v1/remember</button><span class="note">type/confidence/source saved as tags</span></div></div>`));
host.querySelectorAll("input[type=checkbox]").forEach((cb) => cb.onchange = () => { cands[+cb.dataset.i].approved = cb.checked; paint(); });
host.querySelectorAll("select[data-e]").forEach((sl) => sl.onchange = () => { cands[+sl.dataset.e].expert = sl.value; });
$("#go", host).onclick = commit;
}
async function commit() {
const scope = $("#bscope").value || "/"; const ap = cands.filter((c) => c.approved);
const w = $("#commit"); w.innerHTML = `<div class="card" style="margin-top:14px"><h2>Commit</h2><div class="log" id="log"></div><div class="row" style="margin-top:12px"><button id="ti" class="ghost">Test recall →</button></div></div>`;
const log = $("#log", w), line = (h) => { log.appendChild(el(`<div>${h}</div>`)); log.scrollTop = log.scrollHeight; };
line(`<span class="ok">remember.batch --scope ${esc(scope)} --count ${ap.length}</span>`);
for (const c of ap) {
try { const it = await MC.remember({ content: c.content, expert: c.expert, scope, importance: c.importance, tags: c.tags.concat([`type:${c.type}`, `confidence:${c.confidence}`, "source:console"]) });
line(`POST /v1/remember expert=${esc(c.expert)} <span class="code">201 ${esc(it.id)}</span>`); }
catch (e) { line(`<span class="err">FAILED ${esc(e.message)}</span>`); }
}
line(`<span class="ok">done · ${ap.length} written</span>`); await refreshStore();
$("#ti", w).onclick = () => { state.tab = "inspector"; render(); };
}
}
// ---- Memory ----
function vMemory(v) {
v.appendChild(el(`<div><h1>Memory</h1><p class="sub">Browse, filter, and forget stored items.</p>
<div class="card"><div class="row">
<div style="flex:0 1 220px"><label>Expert</label><select id="fe"><option value="">All experts</option>${state.experts.map((e) => `<option value="${esc(e.id)}">${esc(e.name)}</option>`).join("")}</select></div>
<div style="flex:0 1 260px"><label>Scope</label><select id="fs"><option value="">All scopes</option>${state.scopes.map((s) => `<option value="${esc(s.id)}" ${s.id === state.scope ? "selected" : ""}>${esc(s.label)}</option>`).join("")}</select></div>
<button id="rf" class="ghost">Refresh</button></div></div>
<div id="rows" class="card" style="margin-top:14px"></div></div>`));
async function load() {
let items = []; try { items = (await MC.items({ expert: $("#fe").value, scope: $("#fs").value })).items; } catch (e) {}
const h = $("#rows"); h.innerHTML = `<h2>${items.length} item${items.length === 1 ? "" : "s"}</h2>` + (items.length ? `<table><thead><tr><th>Expert</th><th>Content</th><th>Scope</th><th>Tags</th><th></th></tr></thead><tbody>${items.map((it) => `<tr><td><span class="chip on">${esc(it.expert)}</span></td><td>${esc(it.content)}</td><td class="mono dim">${esc(it.scope)}</td><td>${(it.tags || []).map((t) => `<span class="tag">${esc(t)}</span>`).join(" ")}</td><td class="right"><button class="ghost sm" data-d="${esc(it.id)}">Forget</button></td></tr>`).join("")}</tbody></table>` : '<div class="dim">no items</div>');
h.querySelectorAll("button[data-d]").forEach((b) => b.onclick = async () => { await MC.forget(b.dataset.d); await refreshStore(); load(); });
}
$("#rf", v).onclick = load; $("#fe", v).onchange = load; $("#fs", v).onchange = load; load();
}
// ---- Experts ----
function vExperts(v) {
const c = counts("expert");
v.appendChild(el(`<div><h1>Context experts</h1><p class="sub">The typed partitions the router selects between.</p>
<div class="grid cols-2">${state.experts.map((e) => `<div class="card"><div class="row" style="justify-content:space-between"><span class="chip on">${esc(e.name)}</span><span class="mono dim">${c[e.id] || 0} items</span></div><p class="muted" style="margin:10px 0 0">${esc(e.desc)}</p></div>`).join("")}</div></div>`));
}
// ---- Routing ----
function vRouting(v) {
v.appendChild(el(`<div><h1>Routing</h1><p class="sub">The router debugger — per-expert scores and the decision reason.</p>
<div class="card"><div class="row"><div style="flex:1"><label>Query</label><input id="q" value="can the agent store secrets?"/></div><button id="run">Explain</button></div></div><div id="out"></div></div>`));
$("#run", v).onclick = async () => {
const o = $("#out"); o.innerHTML = '<p class="dim" style="margin-top:14px">…</p>';
let r; try { r = await MC.routerExplain($("#q").value, { scope: state.scope }); } catch (e) { o.innerHTML = `<p class="reason">${esc(e.message)}</p>`; return; }
const max = Math.max.apply(null, r.scores.map((s) => s.score).concat([0.0001]));
o.innerHTML = `<div class="card" style="margin-top:14px"><h2>Decision <span class="dim" style="text-transform:none">— ${esc(r.reason)}</span></h2><div style="margin-bottom:10px">${r.selected.map((e) => `<span class="chip on">${esc(e)}</span>`).join("")}${r.unselected.map((e) => `<span class="chip">${esc(e)}</span>`).join("")}</div><table><tbody>${r.scores.map((s) => { const on = r.selected.indexOf(s.expert) >= 0; return `<tr><td>${on ? "● " : ""}${esc(s.expert)}</td><td class="mono">${s.score.toFixed(3)}</td><td><div class="bar"><span style="width:${(100 * s.score / max).toFixed(0)}%;${on ? "" : "background:#2c5b46"}"></span></div></td></tr>`; }).join("")}</tbody></table></div>`;
};
}
// ---- Benchmarks ----
function vBench(v) {
const bar = (val, color) => `<div class="bar" style="display:inline-block;width:120px;vertical-align:middle"><span style="width:${val}%;background:${color || "var(--acc)"}"></span></div> <span class="mono">${val}%</span>`;
v.appendChild(el(`<div><h1>Benchmarks</h1><p class="sub">Robustness on the public MoC-RAG Benchmark. ${esc(BENCH.note)}. <b>BM25 is strong on keyword queries; MoC-RAG is more robust under paraphrase/adversarial.</b></p>
<div class="card"><h2>Recall@8 by query type</h2><table><thead><tr><th>Method</th><th>keyword</th><th>paraphrased</th><th>adversarial</th><th>hard distractors ↓</th></tr></thead><tbody>${BENCH.rows.map((r) => { const moc = r.m.indexOf("moc") === 0; return `<tr><td>${moc ? '<span class="chip on">' + esc(r.m) + "</span>" : esc(r.m)}</td><td>${bar(r.kw)}</td><td>${bar(r.pa)}</td><td>${bar(r.adv, moc ? "var(--acc)" : "var(--amber)")}</td><td class="mono">${r.hd}</td></tr>`; }).join("")}</tbody></table><p class="note">Honest claim: MoC-RAG improves robustness and context efficiency under typed, adversarial conditions — it does not universally beat all RAG.</p></div></div>`));
}
// ---- Standard ----
function vStandard(v) {
v.appendChild(el(`<div><h1>MoC Contract</h1><p class="sub">A frozen, versioned, inspectable wire contract — implement it and claim compatibility.</p>
<div class="grid cols-3"><div class="card"><div class="lbl">Contract</div><div class="stat">${state.version ? esc(state.version.contract) : "—"}</div></div><div class="card"><div class="lbl">Implementation</div><div class="stat" style="font-size:18px">${state.version ? esc(state.version.implementation + " " + state.version.build) : "—"}</div></div><div class="card"><div class="lbl">Conformance</div><div class="stat acc" style="font-size:18px">${state.online ? "MoC API v1 ✓" : "—"}</div></div></div>
<div class="card" style="margin-top:14px"><h2>Endpoints</h2><div>${ENDPOINTS.map((e) => `<span class="chip">${esc(e)}</span>`).join("")}</div><div class="install" style="margin-top:12px">python -m moc_contract.conformance --url ${esc(location.origin)}</div></div></div>`));
}
// ---- Integrate (simple usage for agents) ----
function snippet(title, code) {
const id = "sn" + Math.random().toString(36).slice(2, 8);
return `<div class="card" style="margin-top:14px"><div class="row" style="justify-content:space-between;align-items:center"><h2 style="margin:0">${esc(title)}</h2><button class="ghost sm" data-copy="${id}">Copy</button></div><pre id="${id}" style="margin-top:10px">${esc(code)}</pre></div>`;
}
function vIntegrate(v) {
const origin = location.origin;
const py = `from matrix_context import ContextManager
ctx = ContextManager.create("my-agent", path="agent.db")
def chat(user_msg, scope="/"):
# BEFORE the model call: routed, budgeted, inspectable context
pack = ctx.build_pack(user_msg, scope=scope, max_tokens=400)
answer = your_llm(pack.to_prompt() + "\\nUser: " + user_msg)
# AFTER the turn: remember it so the agent accumulates memory
ctx.remember(user_msg, expert="episodic", scope=scope)
ctx.remember(answer, expert="semantic", scope=scope)
return answer`;
const rest = `# BEFORE: a prompt-ready, routed pack
curl -s ${origin}/v1/pack -H 'content-type: application/json' \\
-d '{"query":"what did we decide?","max_tokens":400}'
# AFTER: remember the turn
curl -s ${origin}/v1/remember -H 'content-type: application/json' \\
-d '{"content":"...","expert":"episodic"}'`;
const mcp = `# Agent-native binding (MoC Contract v1 over MCP)
matrix-context serve --transport stdio`;
v.appendChild(el(`<div>
<h1>Integrate an agent</h1>
<p class="sub">Give any agent typed, inspectable memory in two calls per turn — <b>build_pack</b> before the model call, <b>remember</b> after. This server's live API base is <span class="mono acc">${esc(origin)}/v1</span>.</p>
<div class="install">pip install matrix-context</div>
${snippet("Python — the agent loop", py)}
${snippet("REST — any language", rest)}
${snippet("MCP — agent-native (binding pending)", mcp)}
<p class="note">Full guide: <span class="mono">tutorials/build-your-first-chatbot.md</span> · this endpoint passes <span class="acc">MoC API v1</span>.</p>
</div>`));
v.querySelectorAll("button[data-copy]").forEach((b) => b.onclick = async () => {
try { await navigator.clipboard.writeText($("#" + b.dataset.copy).textContent); b.textContent = "Copied ✓"; setTimeout(() => { b.textContent = "Copy"; }, 1200); }
catch (e) { b.textContent = "Select & copy"; }
});
}
// ---- Settings ----
function vSettings(v) {
v.appendChild(el(`<div><h1>Settings</h1><p class="sub">Connection, tenancy, and display. This console is served same-origin against the live backend.</p>
<div class="card"><h2>Connection</h2>
<div class="kv"><span class="muted">API base</span><span class="mono">${esc(MC.base)}</span></div>
<div class="kv"><span class="muted">Status</span><span class="mono ${state.online ? "acc" : "reason"}">${state.online ? "online" : "offline"}</span></div>
<label style="margin-top:12px">Bearer token (optional — for protected servers)</label>
<div class="row"><div style="flex:1"><input id="tok" type="password" placeholder="paste token" value="${MC.hasToken() ? "********" : ""}"/></div><button id="savetok" class="ghost">Save</button></div>
</div>
<div class="card" style="margin-top:14px"><h2>Default scope (tenant isolation)</h2>
<div class="row"><div style="flex:1"><select id="defscope"><option value="/">All scopes</option>${state.scopes.map((s) => `<option value="${esc(s.id)}" ${s.id === state.scope ? "selected" : ""}>${esc(s.label)}</option>`).join("")}</select></div></div>
<p class="note">Drives the Inspector, Ingest, Memory, and Routing defaults. Also selectable from the top bar.</p></div>
<div class="card" style="margin-top:14px"><h2>Display</h2><div class="row"><button id="rain" class="ghost">${window.__rainOff ? "Enable" : "Disable"} matrix rain</button></div></div></div>`));
$("#savetok", v).onclick = () => { const t = $("#tok").value; if (t && t !== "********") { MC.setToken(t); boot(); } };
$("#defscope", v).onchange = (e) => { state.scope = e.target.value; chrome(); };
$("#rain", v).onclick = () => { window.__rainOff = !window.__rainOff; render(); };
}
// ---- mount (single innerHTML root — all sections render) ----
function mount() {
const root = $("#app");
root.innerHTML = `<div class="top">
<div class="brand"><img src="/assets/logo.svg" alt=""/> Matrix Context <span class="dim" style="font-weight:400">Console</span></div>
<span id="ver" class="pill mono">—</span>
<label class="lbl" style="margin:0 0 0 6px">scope</label>
<select id="scopesel" class="pill" style="padding:4px 10px;max-width:220px"><option value="/">All scopes</option></select>
<span class="spacer"></span><span id="health" class="pill">● connecting…</span>
</div>
<div id="banner" class="banner">Backend offline — start it (<span class="mono">python frontend/server.py</span>) or check Settings, then reload.</div>
<div class="layout">
<nav class="side">${NAV.map(([g, items]) => `<div class="navgroup"><div class="lbl">${g}</div>${items.map(([id, label, ic]) => `<div class="tab" data-tab="${id}"><span class="ic">${ic}</span><span class="t">${label}</span></div>`).join("")}</div>`).join("")}</nav>
<main class="main" id="view"></main>
</div>`;
root.querySelectorAll(".tab").forEach((t) => t.onclick = () => { state.tab = t.dataset.tab; render(); });
$("#scopesel").onchange = (e) => { state.scope = e.target.value; render(); };
boot();
}
document.addEventListener("DOMContentLoaded", mount);
})();
|