@konneal/engine 0.2.93 → 0.2.95
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/{ask-RP2Z7CIV.js → ask-KKOQH7HK.js} +3 -3
- package/dist/{chunk-PE2D5MFD.js → chunk-AJU6LMY3.js} +20 -8
- package/dist/{chunk-WZKLWK7E.js → chunk-CX3OVN3V.js} +8 -4
- package/dist/{chunk-3BL223VD.js → chunk-PTCDEFI3.js} +28 -0
- package/dist/{chunk-TJTEBS4S.js → chunk-ZLQMRQOV.js} +1 -1
- package/dist/{search-G76DK4AF.js → search-CGQFGYTR.js} +2 -2
- package/dist/{tools-SVP6MKBR.js → tools-Z4HQH3QU.js} +1 -1
- package/dist/worker_public/src/index.js +26 -13
- package/package.json +1 -1
- package/workers/worker_public/src/ask.ts +7 -2
- package/workers/worker_public/src/mcp.ts +36 -8
- package/workers/worker_public/src/modelplane.ts +16 -4
- package/workers/worker_public/src/stages/index.ts +2 -0
- package/workers/worker_public/src/stages/licensedLane.ts +38 -0
- package/workers/worker_public/src/stages/types.ts +4 -0
- package/workers/worker_public/src/tools-content.ts +23 -7
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handleAsk
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-CX3OVN3V.js";
|
|
4
|
+
import "./chunk-AJU6LMY3.js";
|
|
5
|
+
import "./chunk-PTCDEFI3.js";
|
|
6
6
|
import "./chunk-LOBYXEVD.js";
|
|
7
7
|
import "./chunk-SPKPH54J.js";
|
|
8
8
|
import "./chunk-A3QHHUN5.js";
|
|
@@ -148,9 +148,11 @@ async function bindModelNode(env, opts) {
|
|
|
148
148
|
};
|
|
149
149
|
if (opts.standard) return gate(await fetchNode(env, opts.standard, nodeId));
|
|
150
150
|
try {
|
|
151
|
-
const rows = await env.DB.prepare(
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
const rows = await env.DB.prepare(
|
|
152
|
+
"SELECT n.standard AS standard FROM model_nodes n LEFT JOIN model_plane_meta m ON m.standard = n.standard WHERE n.node_id = ?1 ORDER BY m.indexed_at DESC, n.standard DESC LIMIT 1"
|
|
153
|
+
).bind(nodeId).all();
|
|
154
|
+
const standard = (rows?.results ?? []).map((r) => String(r.standard))[0];
|
|
155
|
+
if (standard) return gate(await fetchNode(env, standard, nodeId));
|
|
154
156
|
return null;
|
|
155
157
|
} catch {
|
|
156
158
|
return null;
|
|
@@ -754,17 +756,17 @@ var verdictEvaluate = {
|
|
|
754
756
|
description: "Deterministically evaluate a model-plane node's machine checks (OCL boolean expressions, threshold limits) against the quantities a question states. Returns pass/fail with every check's expression and values, or void with the missing parameter names when the question does not state enough. The machine computes; cite the node's clause.",
|
|
755
757
|
params: [
|
|
756
758
|
{ key: "node_id", required: true, description: "the model-plane node id, e.g. /req/metrological/repeatability (node ids appear in answers' verdict blocks)" },
|
|
757
|
-
{ key: "question", required: true, description: "the statement carrying the quantities, e.g. 'is mpe 0.02 with n_lc 3000 within the limit?'" }
|
|
759
|
+
{ key: "question", required: true, description: "the statement carrying the quantities, e.g. 'is mpe 0.02 with n_lc 3000 within the limit?'" },
|
|
760
|
+
{ key: "standard", required: false, description: "the package id when the node id indexes under several standards, as the ambiguity message names it" }
|
|
758
761
|
],
|
|
759
762
|
audiences: ["mcp"],
|
|
760
763
|
handler: async (env, args) => {
|
|
761
764
|
const node_id = String(args?.node_id ?? "").trim();
|
|
762
765
|
const question = String(args?.question ?? "").trim();
|
|
766
|
+
const standard = args?.standard ? String(args.standard).trim() : null;
|
|
763
767
|
if (!node_id.startsWith("/") || question.length < 4) return null;
|
|
764
768
|
try {
|
|
765
|
-
const rows = await env.DB.prepare(
|
|
766
|
-
"SELECT standard, kind, name, content FROM model_nodes WHERE node_id = ?1 LIMIT 2"
|
|
767
|
-
).bind(node_id).all();
|
|
769
|
+
const rows = standard ? await env.DB.prepare("SELECT standard, kind, name, content FROM model_nodes WHERE node_id = ?1 AND standard = ?2 LIMIT 2").bind(node_id, standard).all() : await env.DB.prepare("SELECT standard, kind, name, content FROM model_nodes WHERE node_id = ?1 LIMIT 2").bind(node_id).all();
|
|
768
770
|
const found = rows.results ?? [];
|
|
769
771
|
if (found.length !== 1) {
|
|
770
772
|
return {
|
|
@@ -865,7 +867,17 @@ var bibEntry = {
|
|
|
865
867
|
const rows = await env.DB.prepare(
|
|
866
868
|
"SELECT id, kind, label FROM graph_nodes WHERE label = ?1 COLLATE NOCASE LIMIT 5"
|
|
867
869
|
).bind(label).all();
|
|
868
|
-
|
|
870
|
+
let nodes = rows.results ?? [];
|
|
871
|
+
if (!nodes.length) {
|
|
872
|
+
const d = await env.DB.prepare(
|
|
873
|
+
"SELECT canonical_id, docidentifier FROM documents WHERE docidentifier = ?1 COLLATE NOCASE LIMIT 5"
|
|
874
|
+
).bind(label).all();
|
|
875
|
+
nodes = (d.results ?? []).map((r) => ({
|
|
876
|
+
id: r.canonical_id,
|
|
877
|
+
kind: "doc",
|
|
878
|
+
label: r.docidentifier
|
|
879
|
+
}));
|
|
880
|
+
}
|
|
869
881
|
if (!nodes.length) {
|
|
870
882
|
return { name: "bib.entry", query: label, output: `No registry node carries the label "${label}". State this plainly.` };
|
|
871
883
|
}
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
tableRetyped,
|
|
19
19
|
toolNote,
|
|
20
20
|
verdictNote
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-AJU6LMY3.js";
|
|
22
22
|
import {
|
|
23
23
|
NO_CONTEXT,
|
|
24
24
|
answerQuality,
|
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
tokenBudget,
|
|
57
57
|
understandQuery,
|
|
58
58
|
usageTotal
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-PTCDEFI3.js";
|
|
60
60
|
import {
|
|
61
61
|
embed,
|
|
62
62
|
generateOnce,
|
|
@@ -2166,6 +2166,7 @@ ${summary}` }] : [],
|
|
|
2166
2166
|
if (aggregationVerdict) console.log("aggregation engine:", aggregationVerdict.operation, aggregationVerdict.table, "\u2192", aggregationVerdict.value);
|
|
2167
2167
|
let boundaryNote = null;
|
|
2168
2168
|
let boundaryBoost;
|
|
2169
|
+
let licensedDocNumbers;
|
|
2169
2170
|
let editionBoost;
|
|
2170
2171
|
try {
|
|
2171
2172
|
const fam = understanding?.doc ? refCodec().familyOf(understanding.doc) : null;
|
|
@@ -2178,7 +2179,9 @@ ${summary}` }] : [],
|
|
|
2178
2179
|
const lexicalBoost = [boundaryBoost, editionBoost].filter(Boolean).join(" ") || void 0;
|
|
2179
2180
|
if (P().sources?.licensed?.length) {
|
|
2180
2181
|
const match = matchLicensedTopic(q.query, P().sources.licensed);
|
|
2181
|
-
if (match &&
|
|
2182
|
+
if (match && (standardKeys?.has(match.entry.key) ?? false)) {
|
|
2183
|
+
licensedDocNumbers = match.entry.package ? [match.entry.package] : void 0;
|
|
2184
|
+
} else if (match && !(standardKeys?.has(match.entry.key) ?? false)) {
|
|
2182
2185
|
const docNum = match.entry.doc_number ?? "";
|
|
2183
2186
|
boundaryBoost = docNum || void 0;
|
|
2184
2187
|
let citing = [];
|
|
@@ -2227,7 +2230,8 @@ Answer account questions from these records ONLY: name the record when you use i
|
|
|
2227
2230
|
optimisticVec,
|
|
2228
2231
|
datasetScope: narrowed ? corpora : null,
|
|
2229
2232
|
standardKeys,
|
|
2230
|
-
lexicalBoost
|
|
2233
|
+
lexicalBoost,
|
|
2234
|
+
licensedDocNumbers
|
|
2231
2235
|
});
|
|
2232
2236
|
stageTiming["retrieve-core"] = Date.now() - tR;
|
|
2233
2237
|
console.log("stage: retrieve", Date.now() - tR, "ms");
|
|
@@ -22522,6 +22522,33 @@ var graphLane = {
|
|
|
22522
22522
|
}
|
|
22523
22523
|
};
|
|
22524
22524
|
|
|
22525
|
+
// workers/worker_public/src/stages/licensedLane.ts
|
|
22526
|
+
var licensedLane = {
|
|
22527
|
+
name: "licensed-lane",
|
|
22528
|
+
failure: "additive",
|
|
22529
|
+
when: (c) => !!c.opts.licensedDocNumbers?.length && c.vector.length > 0,
|
|
22530
|
+
prefetch: (c) => {
|
|
22531
|
+
c.lane["licensed-lane"] = portIndex(c.env, "public").query({
|
|
22532
|
+
vector: c.vector,
|
|
22533
|
+
topK: 12,
|
|
22534
|
+
filter: { standard: { $in: c.opts.licensedDocNumbers } }
|
|
22535
|
+
});
|
|
22536
|
+
},
|
|
22537
|
+
run: async (c) => {
|
|
22538
|
+
const g = await c.lane["licensed-lane"];
|
|
22539
|
+
const seenIds = new Set(c.matches.map((m) => m.id));
|
|
22540
|
+
let merged = 0;
|
|
22541
|
+
for (const m of (g ?? []).slice(0, 10)) {
|
|
22542
|
+
if (!seenIds.has(m.id)) {
|
|
22543
|
+
c.matches.push({ id: m.id, score: m.score * THRESHOLDS.graphLaneDiscount, metadata: m.metadata });
|
|
22544
|
+
seenIds.add(m.id);
|
|
22545
|
+
merged++;
|
|
22546
|
+
}
|
|
22547
|
+
}
|
|
22548
|
+
console.log("licensed lane:", g?.length ?? 0, "hits,", merged, "merged");
|
|
22549
|
+
}
|
|
22550
|
+
};
|
|
22551
|
+
|
|
22525
22552
|
// workers/worker_public/src/stages/multiQuery.ts
|
|
22526
22553
|
var RRF_K = 60;
|
|
22527
22554
|
var multiQuery = {
|
|
@@ -23133,6 +23160,7 @@ var STAGES = [
|
|
|
23133
23160
|
glossary,
|
|
23134
23161
|
conceptGraph,
|
|
23135
23162
|
graphLane,
|
|
23163
|
+
licensedLane,
|
|
23136
23164
|
multiQuery,
|
|
23137
23165
|
subQuery,
|
|
23138
23166
|
poolOpen,
|
|
@@ -4,15 +4,15 @@ import {
|
|
|
4
4
|
handleMemories,
|
|
5
5
|
scoreFaithfulness,
|
|
6
6
|
scoreJudge
|
|
7
|
-
} from "../../chunk-
|
|
7
|
+
} from "../../chunk-CX3OVN3V.js";
|
|
8
8
|
import {
|
|
9
9
|
TOOLS_REGISTRY,
|
|
10
10
|
bindModelNode,
|
|
11
11
|
modelGroundingBlock
|
|
12
|
-
} from "../../chunk-
|
|
12
|
+
} from "../../chunk-AJU6LMY3.js";
|
|
13
13
|
import {
|
|
14
14
|
handleSearch
|
|
15
|
-
} from "../../chunk-
|
|
15
|
+
} from "../../chunk-ZLQMRQOV.js";
|
|
16
16
|
import {
|
|
17
17
|
buildMessages,
|
|
18
18
|
citations,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
sessionFrom,
|
|
35
35
|
telemetry,
|
|
36
36
|
understandQuery
|
|
37
|
-
} from "../../chunk-
|
|
37
|
+
} from "../../chunk-PTCDEFI3.js";
|
|
38
38
|
import {
|
|
39
39
|
cfBlobs,
|
|
40
40
|
embed,
|
|
@@ -967,26 +967,39 @@ async function handleMcp(env, ctx, req, tier, key) {
|
|
|
967
967
|
const method = typeof body?.method === "string" ? body.method : null;
|
|
968
968
|
const id = body?.id ?? null;
|
|
969
969
|
const out = await dispatch(method, body?.params, async (name, args) => {
|
|
970
|
+
const t0 = Date.now();
|
|
971
|
+
try {
|
|
972
|
+
return await callToolOnce(env, ctx, req, tier, key, name, args, t0);
|
|
973
|
+
} catch (e) {
|
|
974
|
+
telemetry(env, ctx, tier, `mcp:${name}`, null, false, 0, await sha256Hex(`${name}:${JSON.stringify(args ?? {})}`), void 0, void 0, { durationMs: Date.now() - t0 });
|
|
975
|
+
throw e;
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
if (out.ok && "accepted" in out) return new Response(null, { status: 202 });
|
|
979
|
+
if (out.ok) {
|
|
980
|
+
if (out.result?.serverInfo) out.result.serverInfo.name = `${P().publisher.id}-rag`;
|
|
981
|
+
return json({ jsonrpc: "2.0", id, result: out.result });
|
|
982
|
+
}
|
|
983
|
+
return json({ jsonrpc: "2.0", id, error: { code: out.code, message: out.message } });
|
|
984
|
+
}
|
|
985
|
+
async function callToolOnce(env, ctx, _req, tier, key, name, args, t0) {
|
|
986
|
+
{
|
|
970
987
|
const inner = new Request("https://internal/mcp", {
|
|
971
988
|
method: "POST",
|
|
972
989
|
headers: { "content-type": "application/json" },
|
|
973
990
|
// stream:false forces the JSON lane (anon defaults to SSE)
|
|
974
991
|
body: JSON.stringify({ ...args, stream: false })
|
|
975
992
|
});
|
|
976
|
-
const { runTool, TOOLS_REGISTRY: TOOLS_REGISTRY2 } = await import("../../tools-
|
|
993
|
+
const { runTool, TOOLS_REGISTRY: TOOLS_REGISTRY2 } = await import("../../tools-Z4HQH3QU.js");
|
|
977
994
|
if (TOOLS_REGISTRY2.some((t) => t.name === name && t.audiences.includes("mcp"))) {
|
|
978
995
|
const r = await runTool({ ...env, DB: env.DB }, { name, args }, "mcp");
|
|
979
996
|
return r ? { tool: r.name, query: r.query, result: r.output } : { error: { message: `tool ${name} returned nothing for the given arguments` } };
|
|
980
997
|
}
|
|
981
|
-
const res = name === "ask" ? await (await import("../../ask-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
if (out.ok) {
|
|
986
|
-
if (out.result?.serverInfo) out.result.serverInfo.name = `${P().publisher.id}-rag`;
|
|
987
|
-
return json({ jsonrpc: "2.0", id, result: out.result });
|
|
998
|
+
const res = name === "ask" ? await (await import("../../ask-KKOQH7HK.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-CGQFGYTR.js")).handleSearch(env, ctx, inner, tier, key);
|
|
999
|
+
const payload = await res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
|
|
1000
|
+
telemetry(env, ctx, tier, `mcp:${name}`, null, !payload?.error, JSON.stringify(payload).length, await sha256Hex(`${name}:${JSON.stringify(args ?? {})}`), void 0, void 0, { durationMs: Date.now() - t0 });
|
|
1001
|
+
return payload;
|
|
988
1002
|
}
|
|
989
|
-
return json({ jsonrpc: "2.0", id, error: { code: out.code, message: out.message } });
|
|
990
1003
|
}
|
|
991
1004
|
|
|
992
1005
|
// workers/shared/router.ts
|
package/package.json
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"playwright": "^1.62.1",
|
|
28
28
|
"yaml": "^2.9.1"
|
|
29
29
|
},
|
|
30
|
-
"version": "0.2.
|
|
30
|
+
"version": "0.2.95",
|
|
31
31
|
"description": "The Konneal engine: the publisher-agnostic build pipeline and API plane for standards intelligence (retrieval, answer contract, verdicts, evaluation).",
|
|
32
32
|
"license": "BSD-3-Clause",
|
|
33
33
|
"type": "module",
|
|
@@ -1017,6 +1017,7 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1017
1017
|
// publication's own clause — surface for a question the document's
|
|
1018
1018
|
// vocabulary alone would miss
|
|
1019
1019
|
let boundaryBoost: string | undefined;
|
|
1020
|
+
let licensedDocNumbers: string[] | undefined;
|
|
1020
1021
|
// the EDITION boost: the grounding pool tilts to the publication's
|
|
1021
1022
|
// ACTIVE edition (the graph's own registry) — the dirty corpus's
|
|
1022
1023
|
// superseded editions otherwise outrank the current ones on shared
|
|
@@ -1037,7 +1038,11 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1037
1038
|
const lexicalBoost = [boundaryBoost, editionBoost].filter(Boolean).join(" ") || undefined;
|
|
1038
1039
|
if (P().sources?.licensed?.length) {
|
|
1039
1040
|
const match = matchLicensedTopic(q.query, P().sources.licensed);
|
|
1040
|
-
if (match &&
|
|
1041
|
+
if (match && (standardKeys?.has(match.entry.key) ?? false)) {
|
|
1042
|
+
// the entitled caller: the licensed lane pulls the package's own
|
|
1043
|
+
// units so they compete with (and outrank) the public restatements
|
|
1044
|
+
licensedDocNumbers = match.entry.package ? [match.entry.package] : undefined;
|
|
1045
|
+
} else if (match && !(standardKeys?.has(match.entry.key) ?? false)) {
|
|
1041
1046
|
const docNum = match.entry.doc_number ?? "";
|
|
1042
1047
|
boundaryBoost = docNum || undefined;
|
|
1043
1048
|
let citing: string[] = [];
|
|
@@ -1106,7 +1111,7 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1106
1111
|
// publications there).
|
|
1107
1112
|
retrieved = await retrieve(env, q.query, { prev, understanding, federate, warmEmbed, graphDocNumbers,
|
|
1108
1113
|
sealScope: declaredScoped ? docScope : null, optimisticHits, optimisticVec,
|
|
1109
|
-
datasetScope: narrowed ? corpora : null, standardKeys, lexicalBoost });
|
|
1114
|
+
datasetScope: narrowed ? corpora : null, standardKeys, lexicalBoost, licensedDocNumbers });
|
|
1110
1115
|
stageTiming["retrieve-core"] = Date.now() - tR;
|
|
1111
1116
|
console.log("stage: retrieve", Date.now() - tR, "ms");
|
|
1112
1117
|
// ── TTFT surgery: the two post-retrieval LLM calls run IN PARALLEL —
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
// mcp-proto.ts (dependency-free, unit-tested). The internal-audience
|
|
7
7
|
// server federates both indexes and lives in its own worker, never here.
|
|
8
8
|
import { json, readJson, type ApiKey } from "./lib/http";
|
|
9
|
+
import { sha256Hex } from "./config.ts";
|
|
10
|
+
import { telemetry } from "./quota.ts";
|
|
9
11
|
import { P } from "./profile.ts";
|
|
10
12
|
import { dispatch } from "./mcp-proto.ts";
|
|
11
13
|
import type { Env } from "./env.ts";
|
|
@@ -24,6 +26,37 @@ export async function handleMcp(
|
|
|
24
26
|
const id = body?.id ?? null;
|
|
25
27
|
|
|
26
28
|
const out = await dispatch(method, body?.params, async (name, args) => {
|
|
29
|
+
const t0 = Date.now();
|
|
30
|
+
try {
|
|
31
|
+
return await callToolOnce(env, ctx, req, tier, key, name, args, t0);
|
|
32
|
+
} catch (e) {
|
|
33
|
+
telemetry(env, ctx, tier, `mcp:${name}`, null, false, 0, await sha256Hex(`${name}:${JSON.stringify(args ?? {})}`), undefined, undefined, { durationMs: Date.now() - t0 });
|
|
34
|
+
throw e;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (out.ok && "accepted" in out) return new Response(null, { status: 202 });
|
|
39
|
+
if (out.ok) {
|
|
40
|
+
if ((out.result as any)?.serverInfo) (out.result as any).serverInfo.name = `${P().publisher.id}-rag`;
|
|
41
|
+
return json({ jsonrpc: "2.0", id, result: out.result });
|
|
42
|
+
}
|
|
43
|
+
return json({ jsonrpc: "2.0", id, error: { code: out.code, message: out.message } });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** One tools/call dispatch, measured: every MCP surface's tool usage
|
|
47
|
+
* lands in the queries table under the mcp:<tool> route — which tools
|
|
48
|
+
* agents actually call becomes countable, per tier, per key. */
|
|
49
|
+
async function callToolOnce(
|
|
50
|
+
env: Env,
|
|
51
|
+
ctx: Background,
|
|
52
|
+
_req: Request,
|
|
53
|
+
tier: "anon" | "key" | "member",
|
|
54
|
+
key: ApiKey | null,
|
|
55
|
+
name: string,
|
|
56
|
+
args: Record<string, unknown>,
|
|
57
|
+
t0: number,
|
|
58
|
+
) {
|
|
59
|
+
{
|
|
27
60
|
const inner = new Request("https://internal/mcp", {
|
|
28
61
|
method: "POST",
|
|
29
62
|
headers: { "content-type": "application/json" },
|
|
@@ -42,13 +75,8 @@ export async function handleMcp(
|
|
|
42
75
|
const res = name === "ask"
|
|
43
76
|
? await (await import("./ask")).handleAsk(env, ctx as any, inner, tier, key)
|
|
44
77
|
: await (await import("./search")).handleSearch(env, ctx as any, inner, tier, key);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (out.ok && "accepted" in out) return new Response(null, { status: 202 });
|
|
49
|
-
if (out.ok) {
|
|
50
|
-
if ((out.result as any)?.serverInfo) (out.result as any).serverInfo.name = `${P().publisher.id}-rag`;
|
|
51
|
-
return json({ jsonrpc: "2.0", id, result: out.result });
|
|
78
|
+
const payload: any = await res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
|
|
79
|
+
telemetry(env, ctx, tier, `mcp:${name}`, null, !payload?.error, JSON.stringify(payload).length, await sha256Hex(`${name}:${JSON.stringify(args ?? {})}`), undefined, undefined, { durationMs: Date.now() - t0 });
|
|
80
|
+
return payload;
|
|
52
81
|
}
|
|
53
|
-
return json({ jsonrpc: "2.0", id, error: { code: out.code, message: out.message } });
|
|
54
82
|
}
|
|
@@ -196,10 +196,22 @@ export async function bindModelNode(
|
|
|
196
196
|
};
|
|
197
197
|
if (opts.standard) return gate(await fetchNode(env, opts.standard, nodeId));
|
|
198
198
|
try {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
199
|
+
// The MECE flip left the retired standards' nodes beside their
|
|
200
|
+
// successors' (the same node id under oiml-r60 and oiml-r60-lml),
|
|
201
|
+
// so ambiguity is the COMMON case now. The plane's own registry
|
|
202
|
+
// breaks the tie: the standard loaded most recently is the
|
|
203
|
+
// canonical layer for that id (the flip's law — the layer owns its
|
|
204
|
+
// units), standard name descending as the deterministic second key;
|
|
205
|
+
// a standard with no meta row (orphaned) sorts last. An id under
|
|
206
|
+
// zero standards still binds to nothing.
|
|
207
|
+
const rows = await env.DB.prepare(
|
|
208
|
+
"SELECT n.standard AS standard FROM model_nodes n LEFT JOIN model_plane_meta m ON m.standard = n.standard WHERE n.node_id = ?1 ORDER BY m.indexed_at DESC, n.standard DESC LIMIT 1",
|
|
209
|
+
)
|
|
210
|
+
.bind(nodeId)
|
|
211
|
+
.all();
|
|
212
|
+
const standard = (rows?.results ?? []).map((r: any) => String(r.standard))[0];
|
|
213
|
+
if (standard) return gate(await fetchNode(env, standard, nodeId));
|
|
214
|
+
return null; // not indexed
|
|
203
215
|
} catch {
|
|
204
216
|
return null;
|
|
205
217
|
}
|
|
@@ -17,6 +17,7 @@ import { hyde } from "./hyde.ts";
|
|
|
17
17
|
import { glossary } from "./glossary.ts";
|
|
18
18
|
import { conceptGraph } from "./conceptGraph.ts";
|
|
19
19
|
import { graphLane } from "./graphLane.ts";
|
|
20
|
+
import { licensedLane } from "./licensedLane.ts";
|
|
20
21
|
import { multiQuery } from "./multiQuery.ts";
|
|
21
22
|
import { subQuery } from "./subQuery.ts";
|
|
22
23
|
import { poolOpen } from "./poolOpen.ts";
|
|
@@ -46,6 +47,7 @@ export const STAGES: Stage[] = [
|
|
|
46
47
|
glossary,
|
|
47
48
|
conceptGraph,
|
|
48
49
|
graphLane,
|
|
50
|
+
licensedLane,
|
|
49
51
|
multiQuery,
|
|
50
52
|
subQuery,
|
|
51
53
|
poolOpen,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Licensed lane (additive): an entitled caller whose question is
|
|
2
|
+
// topically about a licensed standard gets that standard's typed units
|
|
3
|
+
// merged into the pool at the graph lane's discount — the public
|
|
4
|
+
// restatements (the Recommendations' own annexes citing the standard)
|
|
5
|
+
// stop out-ranking the licensed package's own units, the rank-order
|
|
6
|
+
// gap the quality ledger has documented on every damp-heat run since
|
|
7
|
+
// the eleven-standard wave. Unentitled callers never see this lane
|
|
8
|
+
// (license-scope would strip the units anyway — the lane simply does
|
|
9
|
+
// not fire).
|
|
10
|
+
import { THRESHOLDS } from "../config.ts";
|
|
11
|
+
import { portIndex } from "../env.ts";
|
|
12
|
+
import type { Stage } from "./types.ts";
|
|
13
|
+
|
|
14
|
+
export const licensedLane: Stage = {
|
|
15
|
+
name: "licensed-lane",
|
|
16
|
+
failure: "additive",
|
|
17
|
+
when: (c) => !!c.opts.licensedDocNumbers?.length && c.vector.length > 0,
|
|
18
|
+
prefetch: (c) => {
|
|
19
|
+
c.lane["licensed-lane"] = portIndex(c.env, "public").query({
|
|
20
|
+
vector: c.vector,
|
|
21
|
+
topK: 12,
|
|
22
|
+
filter: { standard: { $in: c.opts.licensedDocNumbers } },
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
run: async (c) => {
|
|
26
|
+
const g = (await c.lane["licensed-lane"]!) as any;
|
|
27
|
+
const seenIds = new Set(c.matches.map((m: any) => m.id));
|
|
28
|
+
let merged = 0;
|
|
29
|
+
for (const m of (g ?? []).slice(0, 10)) {
|
|
30
|
+
if (!seenIds.has(m.id)) {
|
|
31
|
+
c.matches.push({ id: m.id, score: m.score * THRESHOLDS.graphLaneDiscount, metadata: m.metadata });
|
|
32
|
+
seenIds.add(m.id);
|
|
33
|
+
merged++;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
console.log("licensed lane:", g?.length ?? 0, "hits,", merged, "merged");
|
|
37
|
+
},
|
|
38
|
+
};
|
|
@@ -20,6 +20,10 @@ export interface RetrieveOptions {
|
|
|
20
20
|
federate?: (query: string) => Promise<Hit[]>;
|
|
21
21
|
warmEmbed?: Promise<number[] | null>;
|
|
22
22
|
graphDocNumbers?: string[];
|
|
23
|
+
/** The licensed standards the entitled, topically-matched question
|
|
24
|
+
* pulls (the licensed lane's metadata filter — the package ids, e.g.
|
|
25
|
+
* iec-60068-2-30). Empty/absent for everyone else. */
|
|
26
|
+
licensedDocNumbers?: string[];
|
|
23
27
|
/** The declared context's HARD seal (TODO.ai-platform/02): when the
|
|
24
28
|
* panel's chip declares a document scope, the CANDIDATE POOL is cut
|
|
25
29
|
* to the publication family before rerank + the top-N cut — the
|
|
@@ -236,21 +236,22 @@ export const verdictEvaluate: ToolSpec = {
|
|
|
236
236
|
params: [
|
|
237
237
|
{ key: "node_id", required: true, description: "the model-plane node id, e.g. /req/metrological/repeatability (node ids appear in answers' verdict blocks)" },
|
|
238
238
|
{ key: "question", required: true, description: "the statement carrying the quantities, e.g. 'is mpe 0.02 with n_lc 3000 within the limit?'" },
|
|
239
|
+
{ key: "standard", required: false, description: "the package id when the node id indexes under several standards, as the ambiguity message names it" },
|
|
239
240
|
],
|
|
240
241
|
audiences: ["mcp"],
|
|
241
242
|
handler: async (env, args) => {
|
|
242
243
|
const node_id = String(args?.node_id ?? "").trim();
|
|
243
244
|
const question = String(args?.question ?? "").trim();
|
|
245
|
+
const standard = args?.standard ? String(args.standard).trim() : null;
|
|
244
246
|
if (!node_id.startsWith("/") || question.length < 4) return null;
|
|
245
247
|
try {
|
|
246
248
|
// the same zero-or-ambiguous rule bindModelNode applies: a node
|
|
247
249
|
// id that indexes under exactly one standard resolves; several
|
|
248
|
-
// or none resolve to nothing — no silent pick
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
.bind(node_id)
|
|
253
|
-
.all();
|
|
250
|
+
// or none resolve to nothing — no silent pick (the standard
|
|
251
|
+
// param is the caller's disambiguator)
|
|
252
|
+
const rows = standard
|
|
253
|
+
? await env.DB.prepare("SELECT standard, kind, name, content FROM model_nodes WHERE node_id = ?1 AND standard = ?2 LIMIT 2").bind(node_id, standard).all()
|
|
254
|
+
: await env.DB.prepare("SELECT standard, kind, name, content FROM model_nodes WHERE node_id = ?1 LIMIT 2").bind(node_id).all();
|
|
254
255
|
const found = (rows.results ?? []) as { standard: string; kind: string; name: string | null; content: string }[];
|
|
255
256
|
if (found.length !== 1) {
|
|
256
257
|
return {
|
|
@@ -362,7 +363,22 @@ export const bibEntry: ToolSpec = {
|
|
|
362
363
|
)
|
|
363
364
|
.bind(label)
|
|
364
365
|
.all();
|
|
365
|
-
|
|
366
|
+
let nodes = ((rows.results ?? []) as { id: string; kind: string; label: string }[]);
|
|
367
|
+
if (!nodes.length) {
|
|
368
|
+
// the docidentifier form ("OIML R 60:2017") is a documents-
|
|
369
|
+
// registry key, not a graph label (labels are titles) — resolve
|
|
370
|
+
// it through the registry and synthesize the node rows
|
|
371
|
+
const d = await env.DB.prepare(
|
|
372
|
+
"SELECT canonical_id, docidentifier FROM documents WHERE docidentifier = ?1 COLLATE NOCASE LIMIT 5",
|
|
373
|
+
)
|
|
374
|
+
.bind(label)
|
|
375
|
+
.all();
|
|
376
|
+
nodes = ((d.results ?? []) as { canonical_id: string; docidentifier: string }[]).map((r) => ({
|
|
377
|
+
id: r.canonical_id,
|
|
378
|
+
kind: "doc",
|
|
379
|
+
label: r.docidentifier,
|
|
380
|
+
}));
|
|
381
|
+
}
|
|
366
382
|
if (!nodes.length) {
|
|
367
383
|
return { name: "bib.entry", query: label, output: `No registry node carries the label "${label}". State this plainly.` };
|
|
368
384
|
}
|