bc-observatory 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server.js +38 -7
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -393,9 +393,10 @@ function normOf(r) {
|
|
|
393
393
|
const symbol = r.kind !== "page";
|
|
394
394
|
const main = /* @__PURE__ */ new Set([...indexTokens(r.name, symbol), ...indexTokens(r.title, symbol), ...r.caption ? indexTokens(r.caption) : []]);
|
|
395
395
|
const own = r.type === "topic" ? new Set(tokenize(r.title)) : null;
|
|
396
|
-
const
|
|
396
|
+
const learn = r.type === "learn";
|
|
397
|
+
const tags = (r.tags ?? []).flatMap((t) => indexTokens(t, learn)).filter((t) => !own?.has(t));
|
|
397
398
|
const eqs = r.type === "object" || symbol ? [tokenize(r.name), ...r.caption ? [tokenize(r.caption)] : []] : [tokenize(r.title)];
|
|
398
|
-
const n = { main: [...main], tags: [...new Set(tags)], text: symbol ? null : indexTokens(r.text ?? ""), eqs };
|
|
399
|
+
const n = { main: [...main], tags: learn ? tags : [...new Set(tags)], text: symbol ? null : indexTokens(r.text ?? ""), eqs };
|
|
399
400
|
NORM.set(r, n);
|
|
400
401
|
return n;
|
|
401
402
|
}
|
|
@@ -783,6 +784,26 @@ function hints(index2, q, hits) {
|
|
|
783
784
|
return out;
|
|
784
785
|
}
|
|
785
786
|
|
|
787
|
+
// ../search/src/learn.ts
|
|
788
|
+
function learnRecords(doc) {
|
|
789
|
+
return doc.rows.map(([path, title, summary, date, h, system, ids]) => {
|
|
790
|
+
const hub = h >= 0 ? doc.hubs[h] : void 0;
|
|
791
|
+
const sys = system ?? hub?.[2] ?? null;
|
|
792
|
+
return {
|
|
793
|
+
path: /^https?:\/\//.test(path) ? path : `${doc.base}${path}`,
|
|
794
|
+
type: "learn",
|
|
795
|
+
title,
|
|
796
|
+
summary,
|
|
797
|
+
tier: "official",
|
|
798
|
+
...sys ? { system: sys } : {},
|
|
799
|
+
...date ? { date } : {},
|
|
800
|
+
...ids?.length ? { tags: ids } : {},
|
|
801
|
+
...hub?.[1] ? { path_label: hub[1] } : {},
|
|
802
|
+
...hub?.[0] ? { hub: hub[0] } : {}
|
|
803
|
+
};
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
|
|
786
807
|
// src/embed.ts
|
|
787
808
|
var MAX_TOKENS = 512;
|
|
788
809
|
function parseModel(tokenizerJson, safetensors, config = {}) {
|
|
@@ -1243,7 +1264,7 @@ ${pageView(md, clean, {}, budget, site)}`;
|
|
|
1243
1264
|
}
|
|
1244
1265
|
|
|
1245
1266
|
// src/server.ts
|
|
1246
|
-
var VERSION = "0.
|
|
1267
|
+
var VERSION = "0.5.0";
|
|
1247
1268
|
var SITE = (process.env.BC_OBSERVATORY_SITE ?? "https://waldo1001.github.io/waldo.BCObservatory/").replace(/\/?$/, "/");
|
|
1248
1269
|
var LOCAL = process.env.BC_OBSERVATORY_LOCAL ? resolve(process.env.BC_OBSERVATORY_LOCAL) : null;
|
|
1249
1270
|
var BUDGET = budgetOf(process.env.BC_OBSERVATORY_MAX_CHARS);
|
|
@@ -1287,6 +1308,12 @@ async function loadIndex() {
|
|
|
1287
1308
|
for (const s of manifest.shards) all.push(...JSON.parse(await shard(s.file, s.sha256)));
|
|
1288
1309
|
pages = all;
|
|
1289
1310
|
const idx = prepare(all.map(pageToRecord));
|
|
1311
|
+
if (manifest.learn) {
|
|
1312
|
+
try {
|
|
1313
|
+
prepare(learnRecords(JSON.parse(await shard(manifest.learn.file, manifest.learn.sha256))).map(pageToRecord), idx);
|
|
1314
|
+
} catch {
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1290
1317
|
let sm = null;
|
|
1291
1318
|
try {
|
|
1292
1319
|
sm = JSON.parse(await dataFile("index/symbols-manifest.json"));
|
|
@@ -1314,7 +1341,10 @@ var line = (r, tag = "") => `- ${r.title}${r.caption ? ` (captioned "${r.caption
|
|
|
1314
1341
|
var text = (t) => ({ content: [{ type: "text", text: t }] });
|
|
1315
1342
|
var symbolHit = (r, tag = "") => `- ${r.name} (${symbolLine(r).replace(/ · /g, ", ")}) path=${r.id}${tag}${r.text ? `
|
|
1316
1343
|
${r.text}` : ""}`;
|
|
1317
|
-
var
|
|
1344
|
+
var learnLine = (r, tag = "") => `- ${r.title} [learn, official${r.date ? `, ${r.date}` : ""}] url=${r.path}${tag}${r.path_label ? `
|
|
1345
|
+
in: ${r.path_label}${r.hub ? ` (hub: ${r.hub})` : ""}` : ""}
|
|
1346
|
+
${r.summary}`;
|
|
1347
|
+
var hitLine = (r, tag = "") => r.kind === "page" && r.page ? r.type === "learn" ? learnLine(r.page, tag) : line(r.page, tag) : symbolHit(r, tag);
|
|
1318
1348
|
var MODEL = {
|
|
1319
1349
|
repo: "minishlab/potion-base-8M",
|
|
1320
1350
|
revision: "bf8b056651a2c21b8d2565580b8569da283cab23",
|
|
@@ -1414,7 +1444,8 @@ async function toolSearch(a) {
|
|
|
1414
1444
|
${hs.map((h) => `Hint: ${h.text}${h.query ? ` (search "${h.query}")` : h.path ? ` (cat("${h.path}"))` : ""}`).join("\n")}` : "";
|
|
1415
1445
|
if (!shown.length) return `No pages match "${a.query}". Try fewer words, or ls("") to browse sections.${note}${hintText}`;
|
|
1416
1446
|
const how = semantic.length && keyword.length && mode === "hybrid" ? "keyword + meaning" : mode === "semantic" && semantic.length ? "meaning" : "keyword";
|
|
1417
|
-
|
|
1447
|
+
const learnNote = shown.some((r) => r.type === "learn") ? "; a Learn article's url opens on learn.microsoft.com, cat(hub) reads its hub" : "";
|
|
1448
|
+
return `${shown.length} results, ${how}${note}${how === "keyword + meaning" || mode === "hybrid" ? ` (exact band: ${exactBand})` : ""} (read one with cat(path)${learnNote}):
|
|
1418
1449
|
${shown.map((r) => hitLine(r, tag(r.id))).join("\n")}${hintText}`;
|
|
1419
1450
|
}
|
|
1420
1451
|
async function toolLs(a) {
|
|
@@ -1535,13 +1566,13 @@ ${a.message}
|
|
|
1535
1566
|
var VIEW = { section: z.string().optional(), offset: z.number().int().min(0).max(1e5).optional(), limit: z.number().int().min(1).max(5e3).optional() };
|
|
1536
1567
|
function createServer() {
|
|
1537
1568
|
const server = new McpServer({ name: "bc-observatory", version: VERSION }, {
|
|
1538
|
-
instructions: "BC Observatory: an agent-first knowledge base of Microsoft Dynamics 365 Business Central (Learn hubs, AL objects from the code for BC28-30, localizations, roadmap features, videos, community posts, code changes: merged pull requests of Microsoft's Business Central repositories, BCApps joined to the AL objects they changed, under changes/, and AL Language extension releases (the marketplace changelog, under releases/)). Every page carries a trust tier (official = Microsoft, community = everyone else) and a review state: say which tier a claim comes from. Never invent AL object ids or version numbers: look them up with get_object. Start with search(), read pages with cat(path), browse with ls(path)."
|
|
1569
|
+
instructions: "BC Observatory: an agent-first knowledge base of Microsoft Dynamics 365 Business Central (Learn hubs, AL objects from the code for BC28-30, localizations, roadmap features, videos, community posts, code changes: merged pull requests of Microsoft's Business Central repositories, BCApps joined to the AL objects they changed, under changes/, and AL Language extension releases (the marketplace changelog, under releases/)). Every page carries a trust tier (official = Microsoft, community = everyone else) and a review state: say which tier a claim comes from. Never invent AL object ids or version numbers: look them up with get_object. Start with search(), read pages with cat(path), browse with ls(path). search() also finds Microsoft Learn articles by title, summary and the identifiers they document (type learn): those are not pages here, open their url on learn.microsoft.com."
|
|
1539
1570
|
});
|
|
1540
1571
|
server.registerTool(
|
|
1541
1572
|
"search",
|
|
1542
1573
|
{
|
|
1543
1574
|
title: "Search the knowledge base",
|
|
1544
|
-
description: "Search every page, and the fields, published events, global procedures and enum values of AL objects, ranked like the site's search. Takes names ('Sales Header'), references ('t36', 'cu 80', 'table 11300 BE'), bare ids ('36') and symbol prefixes ('event: OnAfterPost', 'field: Posting Date', 'proc: CopyToTempLines'); a symbol hit's path ends in its anchor (#event-<Name>, #field-<id>, #proc-<Name>, #value-<ordinal>); cat(path) reads that member alone. Hybrid by default: exact matches stay on top and the rest is fused with a meaning ranking; each hit says [keyword], [meaning] or [both]; mode 'keyword' or 'semantic' for one list. Filters: type (topic, app, feature, object, localization, video, post, change, source, digest, release), tier (official, community), system (finance, sales, ... or an alias such as 'g/l'), country ('BE'), app ('Subscription Billing'), object_type ('table'), kind (page, field, event, proc, value).",
|
|
1575
|
+
description: "Search every page, and the fields, published events, global procedures and enum values of AL objects, ranked like the site's search. Takes names ('Sales Header'), references ('t36', 'cu 80', 'table 11300 BE'), bare ids ('36') and symbol prefixes ('event: OnAfterPost', 'field: Posting Date', 'proc: CopyToTempLines'); a symbol hit's path ends in its anchor (#event-<Name>, #field-<id>, #proc-<Name>, #value-<ordinal>); cat(path) reads that member alone. Learn articles too: type learn, a url, not a path. Hybrid by default: exact matches stay on top and the rest is fused with a meaning ranking; each hit says [keyword], [meaning] or [both]; mode 'keyword' or 'semantic' for one list. Filters: type (topic, learn, app, feature, object, localization, video, post, change, source, digest, release), tier (official, community), system (finance, sales, ... or an alias such as 'g/l'), country ('BE'), app ('Subscription Billing'), object_type ('table'), kind (page, field, event, proc, value).",
|
|
1545
1576
|
inputSchema: { query: z.string(), type: z.string().optional(), tier: z.string().optional(), system: z.string().optional(), country: z.string().optional(), app: z.string().optional(), object_type: z.string().optional(), kind: z.enum(["page", "field", "event", "proc", "value"]).optional(), limit: z.number().int().min(1).max(50).optional(), mode: z.enum(["hybrid", "keyword", "semantic"]).optional() }
|
|
1546
1577
|
},
|
|
1547
1578
|
async (a) => text(await toolSearch(a))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bc-observatory",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "MCP server for BC Observatory: an agent-first, cross-referenced knowledge base of Microsoft Dynamics 365 Business Central (Learn, code, roadmap, videos, community blogs).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|