/* Matrix Context Console — Phase 0 (Compatible Mode), zero-dependency SPA. * Talks to the live backend through window.MC (api.js). No build step, no CDN. */ (function () { "use strict"; const MC = window.MC; const INGEST_NATIVE = false; // Phase-2 native ingest stays OFF in Phase 0 const $ = (s, r) => (r || document).querySelector(s); const el = (html) => { const t = document.createElement("template"); t.innerHTML = html.trim(); return t.content.firstChild; }; const esc = (s) => String(s == null ? "" : s).replace(/[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ }[c])); const state = { tab: "overview", experts: [], scopes: [], items: [], online: false, version: null, health: null }; // ----------------------------------------------------------------- client classifier (Compatible Mode) const SAMPLE = `# Matrix-Context architecture notes ## Decision: dual surface Matrix Context exposes both a Python SDK and an MCP server so agents and human operators share one memory plane. ## Decision: SQLite is the default backend Ship SQLite as the default store; vectors are an accelerator, SQL is the source of truth. ## Policy: never store secrets The agent must never store API keys, tokens, or PII in durable memory. ## Preference: local-first The team prefers local-first tools over cloud services by default. ## Roadmap: defer Milvus to v2 Milvus support is deferred to v2; pgvector lands in v1.`; const EXPERT_FOR_TYPE = { decision: "semantic", fact: "semantic", rule: "policy", policy: "policy", preference: "profile", profile: "profile", event: "episodic", episode: "episodic", document: "document", architecture: "semantic" }; 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)\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"; else if (/\b(roadmap|defer|milestone|phase|v1|v2)\b/.test(low)) type = "decision"; const expertExists = (id) => state.experts.some((e) => e.id === id); let expert = EXPERT_FOR_TYPE[type] || "semantic"; if (!expertExists(expert)) expert = (state.experts[0] && state.experts[0].id) || "semantic"; const importance = Math.min(0.98, 0.5 + (type === "decision" ? 0.35 : type === "rule" ? 0.4 : 0.2) + Math.min(0.1, b.length / 4000)); const confidence = Math.round((0.7 + Math.random() * 0.25) * 100) / 100; const tags = Array.from(new Set((low.match(/\b(mcp|sdk|api|sqlite|milvus|pgvector|policy|secrets|local-first|memory|scope|expert)\b/g) || []))).slice(0, 4); return { id: "cand_" + (i + 1), content: b.slice(0, 280), type, expert, importance: Math.round(importance * 100) / 100, confidence, tags: tags.length ? tags : ["context"], approved: true }; }); } // ----------------------------------------------------------------- boot 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) {} } paintChrome(); render(); } function paintChrome() { const pill = $("#health-pill"); pill.className = "pill " + (state.online ? "ok" : "bad"); pill.textContent = state.online ? "● backend online" : "● backend offline"; $("#ver-pill").textContent = state.version ? ("contract " + state.version.contract + " · " + state.version.build) : "—"; $("#offline-banner").classList.toggle("show", !state.online); } function counts(field) { const m = {}; state.items.forEach((it) => { m[it[field]] = (m[it[field]] || 0) + 1; }); return m; } // ----------------------------------------------------------------- tabs const TABS = [ ["overview", "Overview", "01"], ["ingest", "Ingest", "02"], ["memory", "Memory", "03"], ["inspector", "Inspector", "04"], ["experts", "Experts", "05"], ]; function render() { document.querySelectorAll(".tab").forEach((t) => t.classList.toggle("active", t.dataset.tab === state.tab)); const v = $("#view"); v.innerHTML = ""; ({ overview: viewOverview, ingest: viewIngest, memory: viewMemory, inspector: viewInspector, experts: viewExperts }[state.tab] || viewOverview)(v); } // ----------------------------------------------------------------- Overview function viewOverview(v) { const expCount = counts("expert"), scCount = counts("scope"); v.appendChild(el(`

Overview

Inspectable, typed memory for AI agents — MoC Contract v1 backend.

Memory items
${state.health ? state.health.items : "—"}
Experts
${state.experts.length}
Scopes
${state.scopes.length}

Experts

${state.experts.map((e) => `
${esc(e.name)}${expCount[e.id] || 0}
`).join("") || '
none
'}

Scopes

${state.scopes.map((s) => `
${esc(s.label)}${scCount[s.id] || 0}
`).join("") || '
none
'}

Backend

Implementation${state.version ? esc(state.version.implementation + " " + state.version.build) : "—"}
Contract${state.version ? esc(state.version.contract) : "—"}
ConformanceMoC API v1 Compatible
`)); } // ----------------------------------------------------------------- Ingest (Compatible Mode wizard) let candidates = []; function viewIngest(v) { const expOpts = state.experts.map((e) => ``).join(""); v.appendChild(el(`

Ingest

Paste content, review the typed candidates, approve, then commit. Nothing is written until you commit. Compatible Mode — client-side chunking → POST /v1/remember

`)); $("#loadSample", v).onclick = () => { $("#src").value = SAMPLE; }; $("#analyze", v).onclick = () => { candidates = classify($("#src").value); renderCands(); }; function renderCands() { const host = $("#cands"); host.innerHTML = ""; if (!candidates.length) return; const approved = candidates.filter((c) => c.approved).length; host.appendChild(el(`

Review candidates — ${approved}/${candidates.length} approved

${candidates.map((c, i) => ``).join("")}
TypeContentExpertImp.Tags
${esc(c.type)} ${esc(c.content)} ${c.importance} ${c.tags.map((t) => `${esc(t)}`).join(" ")}
metadata (type, confidence, source) is stored as tags until the schema extends
`)); host.querySelectorAll("input[type=checkbox]").forEach((cb) => cb.onchange = () => { candidates[+cb.dataset.i].approved = cb.checked; renderCands(); }); host.querySelectorAll("select[data-exp]").forEach((sl) => sl.onchange = () => { candidates[+sl.dataset.exp].expert = sl.value; }); $("#commit", host).onclick = commit; } async function commit() { const scope = $("#scope").value || "/"; const approved = candidates.filter((c) => c.approved); const wrap = $("#commitWrap"); wrap.innerHTML = `

Commit

`; const log = $("#log", wrap); const line = (h) => { log.appendChild(el(`
${h}
`)); log.scrollTop = log.scrollHeight; }; line(`remember.batch --scope ${esc(scope)} --count ${approved.length}`); for (const c of approved) { try { const tags = c.tags.concat([`type:${c.type}`, `confidence:${c.confidence}`, "source:console"]); const item = await MC.remember({ content: c.content, expert: c.expert, scope, importance: c.importance, tags }); line(`POST /v1/remember expert=${esc(c.expert)} 201 ${esc(item.id)}`); } catch (e) { line(`FAILED: ${esc(e.message)}`); } } line(`done · ${approved.length} items written`); try { state.items = (await MC.items()).items; state.health = await MC.health(); paintChrome(); } catch (e) {} $("#goInspect", wrap).onclick = () => { state.tab = "inspector"; render(); }; } } // ----------------------------------------------------------------- Memory async function viewMemory(v) { v.appendChild(el(`

Memory

Browse and forget stored items.

`)); async function load() { const f = { expert: $("#fExpert").value, scope: $("#fScope").value }; let items = []; try { items = (await MC.items(f)).items; } catch (e) {} const host = $("#rows"); host.innerHTML = `

${items.length} item${items.length === 1 ? "" : "s"}

` + (items.length ? `${items.map((it) => ``).join("")}
ExpertContentScopeImp.Tags
${esc(it.expert)}${esc(it.content)} ${esc(it.scope)}${it.importance} ${(it.tags || []).map((t) => `${esc(t)}`).join(" ")}
` : '
no items
'); host.querySelectorAll("button[data-del]").forEach((b) => b.onclick = async () => { await MC.forget(b.dataset.del); load(); try { state.health = await MC.health(); paintChrome(); } catch (e) {} }); } $("#refresh", v).onclick = load; $("#fExpert", v).onchange = load; $("#fScope", v).onchange = load; load(); } // ----------------------------------------------------------------- Inspector function viewInspector(v) { v.appendChild(el(`

Inspector

See why each item was routed, kept, or dropped — the inspectability contract.

`)); $("#run", v).onclick = async () => { const out = $("#out"); out.innerHTML = '

running…

'; let r; try { r = await MC.inspect($("#q").value, { max_tokens: +$("#mt").value, top_experts: +$("#te").value }); } catch (e) { out.innerHTML = `

${esc(e.message)}

`; return; } const max = Math.max.apply(null, r.routing.scores.map((s) => s.score).concat([0.0001])); out.innerHTML = ""; out.appendChild(el(`

Routing — ${esc(r.routing.reason)}

${r.routing.selected.map((e) => `${esc(e)}`).join("")}${r.routing.unselected.map((e) => `${esc(e)}`).join("")}
${r.routing.scores.map((s) => { const on = r.routing.selected.indexOf(s.expert) >= 0; return ``; }).join("")}
${on ? "● " : ""}${esc(s.expert)}${s.score.toFixed(3)}
`)); out.appendChild(el(`

Context pack ${r.pack.tokens} / ${r.pack.maxTokens} tokens

${r.pack.items.map((p) => { const b = p.breakdown || {}; return ``; }).join("")}${r.pack.dropped.length ? `${r.pack.dropped.map((d) => ``).join("")}` : ""}
ExpertContentScorerel / imp / rec / −red
${esc(p.expert)}${esc(p.content)}${p.final_score}${b.relevance} / ${b.importance} / ${b.recency} / ${b.redundancy}
${esc(d.expert)}${esc(d.id)}${esc(d.reason)}
`)); out.appendChild(el(`

Prompt-ready pack

${esc(r.pack.prompt)}
`)); }; } // ----------------------------------------------------------------- Experts function viewExperts(v) { const c = counts("expert"); v.appendChild(el(`

Experts

The typed context partitions the router selects between.

${state.experts.map((e) => ``).join("")}
ExpertDescriptionItems
${esc(e.name)}${esc(e.desc)}${c[e.id] || 0}
`)); } // ----------------------------------------------------------------- mount function mount() { const root = $("#app"); root.innerHTML = `
Matrix Context Console
● connecting…
`; root.querySelectorAll(".tab").forEach((t) => t.onclick = () => { state.tab = t.dataset.tab; render(); }); boot(); } document.addEventListener("DOMContentLoaded", mount); })();