Spaces:
Sleeping
Sleeping
File size: 5,377 Bytes
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 | /* Matrix Context — live API adapter (Phase 0, Compatible Mode).
*
* Drop-in replacement for the design's mock `window.MC`: same method names,
* real `fetch` against the same-origin `/v1` surface. This is the ONE place that
* maps the backend response shapes to what the UI consumes:
* - remember -> read res.item (backend returns {item:{…}})
* - inspect -> res.routing.* + res.pack.* (selected/unselected/scores/…)
* - version -> contract_version / implementation_version
* - scopes -> plain strings
* No contract changes; works against MoC Contract v1 as-is.
*/
(function () {
const BASE = location.origin + "/v1";
// Optional bearer token (Phase 1 servers may require it; harmless if unset).
let TOKEN = (window.localStorage && localStorage.getItem("mc_token")) || "";
function setToken(t) {
TOKEN = t || "";
if (window.localStorage) localStorage.setItem("mc_token", TOKEN);
}
async function call(method, path, body) {
const headers = { "Content-Type": "application/json" };
if (TOKEN) headers["Authorization"] = "Bearer " + TOKEN;
const opt = { method, headers };
if (body !== undefined) opt.body = JSON.stringify(body);
let resp;
try {
resp = await fetch(BASE + path, opt);
} catch (e) {
throw new ApiError(0, "network error — is the backend running?");
}
let data = {};
try { data = await resp.json(); } catch (e) { /* empty body */ }
if (!resp.ok) throw new ApiError(resp.status, (data && data.error) || ("HTTP " + resp.status));
return data;
}
function ApiError(status, message) { this.status = status; this.message = message; }
ApiError.prototype = Object.create(Error.prototype);
const MC = {
base: BASE,
setToken,
hasToken: () => !!TOKEN,
ApiError,
// ---- discovery ----
async health() {
const h = await call("GET", "/health");
return { status: h.status, name: h.name, version: h.version, items: h.items };
},
async version() {
const v = await call("GET", "/version");
return {
contract: v.contract_version,
implementation: v.implementation,
build: v.implementation_version,
name: v.name,
};
},
async experts() {
const r = await call("GET", "/experts");
return (r.experts || []).map((e) => ({ id: e.name, name: e.name, desc: e.description || "" }));
},
async scopes() {
const r = await call("GET", "/scopes");
return (r.scopes || []).map((s) => ({ id: s, label: s })); // plain strings -> objects
},
// ---- items ----
async items(filter) {
filter = filter || {};
const q = [];
if (filter.scope) q.push("scope=" + encodeURIComponent(filter.scope));
if (filter.expert) q.push("expert=" + encodeURIComponent(filter.expert));
const r = await call("GET", "/items" + (q.length ? "?" + q.join("&") : ""));
return { items: r.items || [], count: r.count || 0 };
},
async getItem(id) {
const r = await call("GET", "/items/" + encodeURIComponent(id));
return r.item;
},
// ---- write ----
async remember(item) {
const r = await call("POST", "/remember", {
content: item.content,
expert: item.expert,
scope: item.scope,
importance: item.importance,
tags: item.tags || [],
ttl: item.ttl != null ? item.ttl : null,
});
return r.item; // {id, content, expert, scope, importance, tags, …}
},
async forget(id) {
const r = await call("POST", "/forget", { id });
return !!r.deleted;
},
// ---- recall / inspect ----
async inspect(query, opts) {
opts = opts || {};
const r = await call("POST", "/inspect", {
query,
scope: opts.scope || "/",
max_tokens: opts.max_tokens || 256,
top_experts: opts.top_experts || 3,
pin_experts: opts.pin_experts || [],
});
// Normalize routing.scores (object map) -> sorted array for the UI.
const scores = Object.entries((r.routing && r.routing.scores) || {})
.map(([expert, score]) => ({ expert, score }))
.sort((a, b) => b.score - a.score);
return {
query: r.query,
routing: {
selected: (r.routing && r.routing.selected_experts) || [],
unselected: (r.routing && r.routing.unselected_experts) || [],
scores,
widened: !!(r.routing && r.routing.widened),
reason: (r.routing && r.routing.reason) || "",
},
pack: {
tokens: r.pack && r.pack.tokens,
maxTokens: r.pack && r.pack.max_tokens,
items: (r.pack && r.pack.items) || [],
dropped: (r.pack && r.pack.dropped) || [],
citations: (r.pack && r.pack.citations) || [],
prompt: (r.pack && r.pack.prompt) || "",
},
};
},
async routerExplain(query, opts) {
opts = opts || {};
const r = await call("POST", "/router/explain", {
query, scope: opts.scope || "/", top_experts: opts.top_experts || 3,
});
return {
selected: r.selected_experts || [],
unselected: r.unselected_experts || [],
scores: r.scores || [],
reason: r.reason || "",
widened: !!r.widened,
};
},
};
window.MC = MC;
})();
|