@konneal/engine 0.2.135 → 0.2.136
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.
|
@@ -1981,6 +1981,7 @@ async function handleAsk(env, ctx, req, tier, key) {
|
|
|
1981
1981
|
}
|
|
1982
1982
|
}
|
|
1983
1983
|
let understanding = null;
|
|
1984
|
+
const answerCites = (t) => /\[[^\]]+\]/.test(t);
|
|
1984
1985
|
const refusalScope = (cited) => ({ cited, conversational: understanding?.intent === "conversational" });
|
|
1985
1986
|
let optimisticVec = null;
|
|
1986
1987
|
let optimisticHits = [];
|
|
@@ -2622,7 +2623,7 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
|
|
|
2622
2623
|
}
|
|
2623
2624
|
}
|
|
2624
2625
|
}
|
|
2625
|
-
const canonical0 = usedHits.length > 0 ? exciseMisplacedPin(canonicalRefusal(full, refusalScope(
|
|
2626
|
+
const canonical0 = usedHits.length > 0 ? exciseMisplacedPin(canonicalRefusal(full, refusalScope(answerCites(full))), true) : canonicalRefusal(full, refusalScope(false));
|
|
2626
2627
|
const c2 = canonical0.includes(refusalAnswer()) ? { text: canonical0, blocks: [], dropped: [] } : await contractV2(env.DB, canonical0, usedHits);
|
|
2627
2628
|
send({
|
|
2628
2629
|
type: "done",
|
|
@@ -2660,7 +2661,7 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
|
|
|
2660
2661
|
if (streamed.violations.length > 0) {
|
|
2661
2662
|
console.log("anchors:", streamed.violations.length, "of", streamed.total, "unverified \u2014 not caching");
|
|
2662
2663
|
}
|
|
2663
|
-
if (streamed.violations.length === 0 && canonical.length > 0 && !contextual && !declaredCtx && cacheableAnswer(canonical, refusalScope(
|
|
2664
|
+
if (streamed.violations.length === 0 && canonical.length > 0 && !contextual && !declaredCtx && cacheableAnswer(canonical, refusalScope(answerCites(canonical))) && !ablate) {
|
|
2664
2665
|
ctx.waitUntil(
|
|
2665
2666
|
env.CACHE.put(exactCacheKey(env.INDEX_VERSION, gen, ns, await sha256Hex(cacheKeyMaterial(q.query, q.lang, salt))), JSON.stringify({ answer: canonical, citations: cites, model, query_hash: queryHash, ...sourceQuality ? { source_quality: sourceQuality, confidence_note: streamedNote || qualityNote(sourceQuality) } : {}, ...streamedEntailment ? { entailment: streamedEntailment } : {} }), { expirationTtl: LIMITS.cacheTtlSec })
|
|
2666
2667
|
);
|
|
@@ -2706,7 +2707,7 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
|
|
|
2706
2707
|
);
|
|
2707
2708
|
answer = await generateOnce(env, MODELS.fallback, flat, routeEffort(routed.route));
|
|
2708
2709
|
}
|
|
2709
|
-
if (answer) answer = canonicalRefusal(answer, refusalScope(
|
|
2710
|
+
if (answer) answer = canonicalRefusal(answer, refusalScope(answerCites(answer)));
|
|
2710
2711
|
if (answer && usedHits.length > 0) answer = exciseMisplacedPin(answer, true);
|
|
2711
2712
|
stageTiming.generate = Date.now() - tGen;
|
|
2712
2713
|
let used = usedHits;
|
|
@@ -2731,7 +2732,7 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
|
|
|
2731
2732
|
generateRetries += 1;
|
|
2732
2733
|
const corrected = await generateOnce(env, model, [...messages, { role: "system", content: note }], routeEffort(routed.route));
|
|
2733
2734
|
if (corrected) {
|
|
2734
|
-
const correctedAnswer = canonicalRefusal(corrected, refusalScope(
|
|
2735
|
+
const correctedAnswer = canonicalRefusal(corrected, refusalScope(answerCites(corrected)));
|
|
2735
2736
|
const retryAnchors = checkQuoteAnchors(correctedAnswer, used.map((h) => h.text));
|
|
2736
2737
|
const retryRetyped = tableRetyped(correctedAnswer, hasTableUnit);
|
|
2737
2738
|
if (retryAnchors.violations.length < anchors.violations.length || !retryRetyped && retyped || unreferenced && correctedAnswer.includes("[[u:")) {
|
|
@@ -2756,7 +2757,7 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
|
|
|
2756
2757
|
const { messages: retryMessages, usedHits: retryUsed } = buildMessages(q.query, retryRetrieve.hits, q.lang, keptHistory, void 0, summary, budget);
|
|
2757
2758
|
const retryAnswer = await generateOnce(env, model, retryMessages, routeEffort(routed.route));
|
|
2758
2759
|
if (retryAnswer) {
|
|
2759
|
-
answer = canonicalRefusal(retryAnswer, refusalScope(
|
|
2760
|
+
answer = canonicalRefusal(retryAnswer, refusalScope(answerCites(retryAnswer)));
|
|
2760
2761
|
used = retryUsed;
|
|
2761
2762
|
}
|
|
2762
2763
|
}
|
|
@@ -2788,7 +2789,7 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
|
|
|
2788
2789
|
messages[messages.length - 1]
|
|
2789
2790
|
], effort);
|
|
2790
2791
|
if (regen && !regen.includes(refusalAnswer())) {
|
|
2791
|
-
answer = canonicalRefusal(regen, refusalScope(
|
|
2792
|
+
answer = canonicalRefusal(regen, refusalScope(answerCites(regen)));
|
|
2792
2793
|
console.log("blind-answer: regeneration grounded");
|
|
2793
2794
|
}
|
|
2794
2795
|
}
|
|
@@ -2808,7 +2809,7 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
|
|
|
2808
2809
|
}
|
|
2809
2810
|
}
|
|
2810
2811
|
const out = { answer, citations: finalCites, ...jsonQuality ? { source_quality: jsonQuality, confidence_note: entailmentNote || qualityNote(jsonQuality), ...entailment ? { entailment } : {}, ...jsonQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(finalCites) } : {} } : {}, model: MODELS.member, query_hash: queryHash, follow_ups: understanding?.follow_ups ?? [], blocks: [...c2ns.blocks, ...verdictBlock ? [verdictBlock] : [], ...conditionBlock ? [conditionBlock] : [], ...aggregationBlock ? [aggregationBlock] : [], ...registerBlock ? [registerBlock] : [], ...completionBlocks], context_applied: ctxApplied, ...liveRecords ? { records: liveRecords } : {}, ...ablate ? { ablate } : {}, route: { route: routed.route, features: routed.features } };
|
|
2811
|
-
const cacheable = !contextual && !declaredCtx && !ablate && cacheableAnswer(answer, refusalScope(
|
|
2812
|
+
const cacheable = !contextual && !declaredCtx && !ablate && cacheableAnswer(answer, refusalScope(answerCites(answer))) && finalAnchors.violations.length === 0;
|
|
2812
2813
|
if (cacheable) {
|
|
2813
2814
|
const ck = exactCacheKey(env.INDEX_VERSION, gen, ns, await sha256Hex(cacheKeyMaterial(q.query, q.lang, salt)));
|
|
2814
2815
|
ctx.waitUntil(env.CACHE.put(ck, JSON.stringify(out), { expirationTtl: LIMITS.cacheTtlSec }));
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
handleMemories,
|
|
5
5
|
scoreFaithfulness,
|
|
6
6
|
scoreJudge
|
|
7
|
-
} from "../../chunk-
|
|
7
|
+
} from "../../chunk-YLBPABDQ.js";
|
|
8
8
|
import {
|
|
9
9
|
TOOLS_REGISTRY,
|
|
10
10
|
bindModelNode,
|
|
@@ -877,7 +877,7 @@ ${recent.map((h, n) => `[${n + 1}] ${h.metadata.docidentifier ?? ""} \xA7${h.met
|
|
|
877
877
|
telemetry(env, ctx, "member", "research", MODELS.research, false, 0, queryHash, q.lang);
|
|
878
878
|
throw new Error("The generation model is unavailable; please retry.");
|
|
879
879
|
}
|
|
880
|
-
answer = canonicalRefusal(answer, { cited:
|
|
880
|
+
answer = canonicalRefusal(answer, { cited: /\[[^\]]+\]/.test(answer), conversational: false });
|
|
881
881
|
const anchors = checkQuoteAnchors(answer, used.map((h) => h.text));
|
|
882
882
|
if (anchors.violations.length) console.log("research anchors:", anchors.violations.length, "unverified");
|
|
883
883
|
const out = {
|
|
@@ -1052,7 +1052,7 @@ async function callToolOnce(env, ctx, _req, tier, key, name, args, t0) {
|
|
|
1052
1052
|
const r = await runTool({ ...env, DB: env.DB }, { name, args }, "mcp");
|
|
1053
1053
|
payload = r ? { tool: r.name, query: r.query, result: r.output } : { error: { message: `tool ${name} returned nothing for the given arguments` } };
|
|
1054
1054
|
} else {
|
|
1055
|
-
const res = name === "ask" ? await (await import("../../ask-
|
|
1055
|
+
const res = name === "ask" ? await (await import("../../ask-N5I35VCK.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-LFS5HHMZ.js")).handleSearch(env, ctx, inner, tier, key);
|
|
1056
1056
|
payload = await res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
|
|
1057
1057
|
}
|
|
1058
1058
|
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 });
|
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.136",
|
|
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",
|
|
@@ -627,7 +627,12 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
627
627
|
let understanding: any = null;
|
|
628
628
|
// the loose redirect-offer family's gate (refusal.ts): knowledge-seek
|
|
629
629
|
// questions only, uncited answers only — a conversational turn's
|
|
630
|
-
// scope vocabulary is the answer itself
|
|
630
|
+
// scope vocabulary is the answer itself. "Cited" is the ANSWER TEXT
|
|
631
|
+
// carrying citation markers, NEVER the prompt's hit count: retrieval
|
|
632
|
+
// always returns passages (the model just declines to cite them on a
|
|
633
|
+
// refusal) — gating on usedHits left every refusal "cited" and the
|
|
634
|
+
// wall dark through three deploys (2026-10-11)
|
|
635
|
+
const answerCites = (t: string) => /\[[^\]]+\]/.test(t);
|
|
631
636
|
const refusalScope = (cited: boolean) => ({ cited, conversational: understanding?.intent === "conversational" });
|
|
632
637
|
// a query naming a model node (/req/…, /term/…) is node-SCOPED: its
|
|
633
638
|
// ── Option C: optimistic parallel retrieval ──
|
|
@@ -1541,7 +1546,7 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1541
1546
|
}
|
|
1542
1547
|
// the misplaced-pin wall rides the streamed path too: a
|
|
1543
1548
|
// CITED stream is not a refusal
|
|
1544
|
-
const canonical0 = usedHits.length > 0 ? exciseMisplacedPin(canonicalRefusal(full, refusalScope(
|
|
1549
|
+
const canonical0 = usedHits.length > 0 ? exciseMisplacedPin(canonicalRefusal(full, refusalScope(answerCites(full))), true) : canonicalRefusal(full, refusalScope(false));
|
|
1545
1550
|
// answer contract v2: validate [[u:]] refs, resolve typed blocks
|
|
1546
1551
|
const c2 = canonical0.includes(refusalAnswer())
|
|
1547
1552
|
? { text: canonical0, blocks: [], dropped: [] as string[] }
|
|
@@ -1582,7 +1587,7 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1582
1587
|
if (streamed.violations.length > 0) {
|
|
1583
1588
|
console.log("anchors:", streamed.violations.length, "of", streamed.total, "unverified — not caching");
|
|
1584
1589
|
}
|
|
1585
|
-
if (streamed.violations.length === 0 && canonical.length > 0 && !contextual && !declaredCtx && cacheableAnswer(canonical, refusalScope(
|
|
1590
|
+
if (streamed.violations.length === 0 && canonical.length > 0 && !contextual && !declaredCtx && cacheableAnswer(canonical, refusalScope(answerCites(canonical))) && !ablate) {
|
|
1586
1591
|
ctx.waitUntil(
|
|
1587
1592
|
env.CACHE.put(exactCacheKey(env.INDEX_VERSION, gen, ns, await sha256Hex(cacheKeyMaterial(q.query, q.lang, salt))), JSON.stringify({ answer: canonical, citations: cites, model, query_hash: queryHash, ...(sourceQuality ? { source_quality: sourceQuality, confidence_note: streamedNote || qualityNote(sourceQuality) } : {}), ...(streamedEntailment ? { entailment: streamedEntailment } : {}) }), { expirationTtl: LIMITS.cacheTtlSec }),
|
|
1588
1593
|
);
|
|
@@ -1645,7 +1650,7 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1645
1650
|
);
|
|
1646
1651
|
answer = await generateOnce(env, MODELS.fallback, flat, routeEffort(routed.route));
|
|
1647
1652
|
}
|
|
1648
|
-
if (answer) answer = canonicalRefusal(answer, refusalScope(
|
|
1653
|
+
if (answer) answer = canonicalRefusal(answer, refusalScope(answerCites(answer)));
|
|
1649
1654
|
// the misplaced-pin wall: a CITED answer is not a refusal — excise
|
|
1650
1655
|
// the pinned sentence if the model dropped it in as a disclaimer
|
|
1651
1656
|
// (measured on chip-scoped asks: correct cited answers carrying the
|
|
@@ -1688,7 +1693,7 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1688
1693
|
generateRetries += 1;
|
|
1689
1694
|
const corrected = await generateOnce(env, model, [...messages, { role: "system", content: note }], routeEffort(routed.route));
|
|
1690
1695
|
if (corrected) {
|
|
1691
|
-
const correctedAnswer = canonicalRefusal(corrected, refusalScope(
|
|
1696
|
+
const correctedAnswer = canonicalRefusal(corrected, refusalScope(answerCites(corrected)));
|
|
1692
1697
|
const retryAnchors = checkQuoteAnchors(correctedAnswer, used.map((h: Hit) => h.text));
|
|
1693
1698
|
const retryRetyped = tableRetyped(correctedAnswer, hasTableUnit);
|
|
1694
1699
|
if (retryAnchors.violations.length < anchors.violations.length || (!retryRetyped && retyped) || (unreferenced && correctedAnswer.includes("[[u:"))) {
|
|
@@ -1733,7 +1738,7 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1733
1738
|
const retryAnswer = await generateOnce(env, model, retryMessages, routeEffort(routed.route));
|
|
1734
1739
|
// the answer now comes from the retry passages — citations must follow
|
|
1735
1740
|
if (retryAnswer) {
|
|
1736
|
-
answer = canonicalRefusal(retryAnswer, refusalScope(
|
|
1741
|
+
answer = canonicalRefusal(retryAnswer, refusalScope(answerCites(retryAnswer)));
|
|
1737
1742
|
used = retryUsed;
|
|
1738
1743
|
}
|
|
1739
1744
|
}
|
|
@@ -1785,7 +1790,7 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1785
1790
|
messages[messages.length - 1],
|
|
1786
1791
|
], effort);
|
|
1787
1792
|
if (regen && !regen.includes(refusalAnswer())) {
|
|
1788
|
-
answer = canonicalRefusal(regen, refusalScope(
|
|
1793
|
+
answer = canonicalRefusal(regen, refusalScope(answerCites(regen)));
|
|
1789
1794
|
console.log("blind-answer: regeneration grounded");
|
|
1790
1795
|
}
|
|
1791
1796
|
}
|
|
@@ -1811,7 +1816,7 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1811
1816
|
}
|
|
1812
1817
|
}
|
|
1813
1818
|
const out = { answer, citations: finalCites, ...(jsonQuality ? { source_quality: jsonQuality, confidence_note: entailmentNote || qualityNote(jsonQuality), ...(entailment ? { entailment } : {}), ...(jsonQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(finalCites) } : {}) } : {}), model: MODELS.member, query_hash: queryHash, follow_ups: understanding?.follow_ups ?? [], blocks: [...c2ns.blocks, ...(verdictBlock ? [verdictBlock] : []), ...(conditionBlock ? [conditionBlock] : []), ...(aggregationBlock ? [aggregationBlock] : []), ...(registerBlock ? [registerBlock] : []), ...completionBlocks], context_applied: ctxApplied, ...(liveRecords ? { records: liveRecords } : {}), ...(ablate ? { ablate } : {}), route: { route: routed.route, features: routed.features } };
|
|
1814
|
-
const cacheable = !contextual && !declaredCtx && !ablate && cacheableAnswer(answer, refusalScope(
|
|
1819
|
+
const cacheable = !contextual && !declaredCtx && !ablate && cacheableAnswer(answer, refusalScope(answerCites(answer))) && finalAnchors.violations.length === 0;
|
|
1815
1820
|
if (cacheable) {
|
|
1816
1821
|
const ck = exactCacheKey(env.INDEX_VERSION, gen, ns, await sha256Hex(cacheKeyMaterial(q.query, q.lang, salt)));
|
|
1817
1822
|
ctx.waitUntil(env.CACHE.put(ck, JSON.stringify(out), { expirationTtl: LIMITS.cacheTtlSec }));
|
|
@@ -164,7 +164,7 @@ async function run(
|
|
|
164
164
|
telemetry(env, ctx, "member", "research", MODELS.research, false, 0, queryHash, q.lang);
|
|
165
165
|
throw new Error("The generation model is unavailable; please retry.");
|
|
166
166
|
}
|
|
167
|
-
answer = canonicalRefusal(answer, { cited:
|
|
167
|
+
answer = canonicalRefusal(answer, { cited: /\[[^\]]+\]/.test(answer), conversational: false });
|
|
168
168
|
const anchors = checkQuoteAnchors(answer, used.map((h: Hit) => h.text));
|
|
169
169
|
if (anchors.violations.length) console.log("research anchors:", anchors.violations.length, "unverified");
|
|
170
170
|
const out = {
|