@konneal/engine 0.2.39 → 0.2.41
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-UGTXNPPY.js → ask-3LIAXR4S.js} +2 -2
- package/dist/{chunk-EVCERBIH.js → chunk-AKAFLMIB.js} +1 -1
- package/dist/{chunk-OHYAHQQV.js → chunk-JG5GRJCZ.js} +6 -4
- package/dist/{chunk-NBE7BCQ7.js → chunk-N2UOENDY.js} +16 -3
- package/dist/quality.d.ts +12 -1
- package/dist/{search-G23CY5I6.js → search-QZDQVB57.js} +2 -2
- package/dist/worker_public/src/index.js +4 -4
- package/package.json +1 -1
- package/workers/worker_public/src/ask.ts +12 -5
- package/workers/worker_public/src/quality.ts +25 -4
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
contextNote,
|
|
10
10
|
editionNote,
|
|
11
11
|
embed,
|
|
12
|
+
experimentalSourceLabels,
|
|
12
13
|
generateOnce,
|
|
13
14
|
graphExpand,
|
|
14
15
|
identityNote,
|
|
@@ -34,7 +35,7 @@ import {
|
|
|
34
35
|
syntheticUnderstanding,
|
|
35
36
|
telemetry,
|
|
36
37
|
understandQuery
|
|
37
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-N2UOENDY.js";
|
|
38
39
|
import {
|
|
39
40
|
corsHeaders,
|
|
40
41
|
err,
|
|
@@ -2448,8 +2449,9 @@ Answer account questions from these records ONLY: name the record when you use i
|
|
|
2448
2449
|
);
|
|
2449
2450
|
await attachFigureImages(env, messages, usedHits, q.query);
|
|
2450
2451
|
if (userImage) {
|
|
2452
|
+
const wantsMarkings = /\b(mark(ing|ings)?|nameplate|label|inscription|engrav|sticker|plate)\b|certificat/i.test(q.query);
|
|
2451
2453
|
const last = messages[messages.length - 1];
|
|
2452
|
-
const note = "\n\n(The user attached an image with this question; interpret it directly when answering.)";
|
|
2454
|
+
const note = wantsMarkings ? "\n\n(The user attached a photo with this question. First transcribe every inscription you can actually read in the image \u2014 names, model references, accuracy classes, numeric values with their units, certificate or approval numbers \u2014 quoting them verbatim. Then answer the question from the numbered passages, citing the requirement each interpretation rests on. If an inscription is unreadable, say so; never invent a marking.)" : "\n\n(The user attached an image with this question; interpret it directly when answering.)";
|
|
2453
2455
|
if (Array.isArray(last.content)) {
|
|
2454
2456
|
const textPart = last.content.find((p) => p.type === "text");
|
|
2455
2457
|
if (textPart) textPart.text += note;
|
|
@@ -2475,7 +2477,7 @@ Answer account questions from these records ONLY: name the record when you use i
|
|
|
2475
2477
|
`));
|
|
2476
2478
|
send({ type: "read", read: readAs() });
|
|
2477
2479
|
const sourceQuality = answerQuality(cites.map((c) => c.quality));
|
|
2478
|
-
send({ type: "citations", citations: cites, context_applied: ctxApplied, ...sourceQuality ? { source_quality: sourceQuality,
|
|
2480
|
+
send({ type: "citations", citations: cites, context_applied: ctxApplied, ...sourceQuality ? { source_quality: sourceQuality, confidence_note: qualityNote(sourceQuality), ...sourceQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(cites) } : {} } : {}, ...liveRecords ? { records: liveRecords } : {}, quota });
|
|
2479
2481
|
let full = "";
|
|
2480
2482
|
try {
|
|
2481
2483
|
for await (const tok of sseTokens(stream)) {
|
|
@@ -2609,7 +2611,7 @@ Answer account questions from these records ONLY: name the record when you use i
|
|
|
2609
2611
|
}
|
|
2610
2612
|
completionBlocks.push(...await completeFigures(env.DB, answer, [...c2ns.blocks, ...completionBlocks], used));
|
|
2611
2613
|
const jsonQuality = answerQuality(finalCites.map((c) => c.quality));
|
|
2612
|
-
const out = { answer, citations: finalCites, ...jsonQuality ? { source_quality: jsonQuality,
|
|
2614
|
+
const out = { answer, citations: finalCites, ...jsonQuality ? { source_quality: jsonQuality, confidence_note: qualityNote(jsonQuality), ...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] : [], ...completionBlocks], context_applied: ctxApplied, ...liveRecords ? { records: liveRecords } : {} };
|
|
2613
2615
|
const cacheable = !contextual && !declaredCtx && !answer.includes(refusalAnswer()) && finalAnchors.violations.length === 0;
|
|
2614
2616
|
if (cacheable) {
|
|
2615
2617
|
const warmVec = await warmEmbed ?? null;
|
|
@@ -77,9 +77,21 @@ function answerQuality(qualities) {
|
|
|
77
77
|
return worst;
|
|
78
78
|
}
|
|
79
79
|
function qualityNote(q) {
|
|
80
|
-
if (q === "verified") return "
|
|
81
|
-
if (q === "curated") return "
|
|
82
|
-
return "Partly grounded in experimental
|
|
80
|
+
if (q === "verified") return "High confidence: this publication's requirements ride a machine-checkable data model.";
|
|
81
|
+
if (q === "curated") return "Established sources: Metanorma-edited documents, chunked at clause boundaries.";
|
|
82
|
+
return "WARNING: Partly grounded in experimental data source that was derived from OCR content. Please verify content against official publications.";
|
|
83
|
+
}
|
|
84
|
+
function experimentalSourceLabels(cites, cap = 6) {
|
|
85
|
+
const labels = [];
|
|
86
|
+
for (const c of cites) {
|
|
87
|
+
if (c.quality !== "ocr") continue;
|
|
88
|
+
const id = String(c.docidentifier || c.doc_id || "source");
|
|
89
|
+
const anchor = String(c.clause_anchor ?? "");
|
|
90
|
+
const garbage = /^[0-9a-f]{8}-[0-9a-f]{4}-/i.test(anchor) || anchor.startsWith("_") && anchor.length > 12;
|
|
91
|
+
labels.push(garbage || !anchor || anchor === "overview" ? id : `${id} \xA7${anchor}`);
|
|
92
|
+
if (labels.length >= cap) break;
|
|
93
|
+
}
|
|
94
|
+
return labels;
|
|
83
95
|
}
|
|
84
96
|
|
|
85
97
|
// workers/worker_public/src/lexical.ts
|
|
@@ -24594,6 +24606,7 @@ export {
|
|
|
24594
24606
|
generateOnce,
|
|
24595
24607
|
answerQuality,
|
|
24596
24608
|
qualityNote,
|
|
24609
|
+
experimentalSourceLabels,
|
|
24597
24610
|
ftsMatchQuery,
|
|
24598
24611
|
refCodec,
|
|
24599
24612
|
NO_CONTEXT,
|
package/dist/quality.d.ts
CHANGED
|
@@ -2,5 +2,16 @@ import type { ChunkMeta } from "../../shared/chunk.ts";
|
|
|
2
2
|
export type SourceQuality = "verified" | "curated" | "ocr";
|
|
3
3
|
export declare function hitQuality(m: ChunkMeta): SourceQuality;
|
|
4
4
|
export declare function answerQuality(qualities: (SourceQuality | undefined)[]): SourceQuality | null;
|
|
5
|
-
/** The one-line posture the interface renders under the answer.
|
|
5
|
+
/** The one-line posture the interface renders under the answer. The
|
|
6
|
+
* OCR rung is the owner's 2026-09-26 wording, verbatim. */
|
|
6
7
|
export declare function qualityNote(q: SourceQuality): string;
|
|
8
|
+
/** The citations standing on the OCR rung, named for the reader — the
|
|
9
|
+
* confidence line says WHICH sources are experimental, not just that
|
|
10
|
+
* some are. Producer-UUID anchors say nothing and are dropped; a cap
|
|
11
|
+
* keeps the line readable on citation-heavy answers. */
|
|
12
|
+
export declare function experimentalSourceLabels(cites: {
|
|
13
|
+
quality?: string;
|
|
14
|
+
docidentifier?: string;
|
|
15
|
+
doc_id?: string;
|
|
16
|
+
clause_anchor?: string;
|
|
17
|
+
}[], cap?: number): string[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handleSearch
|
|
3
|
-
} from "../../chunk-
|
|
3
|
+
} from "../../chunk-AKAFLMIB.js";
|
|
4
4
|
import {
|
|
5
5
|
bindModelNode,
|
|
6
6
|
checkQuoteAnchors,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
modelGroundingBlock,
|
|
10
10
|
scoreJudge,
|
|
11
11
|
standardForDocNumber
|
|
12
|
-
} from "../../chunk-
|
|
12
|
+
} from "../../chunk-JG5GRJCZ.js";
|
|
13
13
|
import {
|
|
14
14
|
buildMessages,
|
|
15
15
|
citations,
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
sessionFrom,
|
|
36
36
|
telemetry,
|
|
37
37
|
understandQuery
|
|
38
|
-
} from "../../chunk-
|
|
38
|
+
} from "../../chunk-N2UOENDY.js";
|
|
39
39
|
import {
|
|
40
40
|
authenticate,
|
|
41
41
|
corsHeaders,
|
|
@@ -999,7 +999,7 @@ async function handleMcp(env, ctx, req, tier, key) {
|
|
|
999
999
|
// stream:false forces the JSON lane (anon defaults to SSE)
|
|
1000
1000
|
body: JSON.stringify({ ...args, stream: false })
|
|
1001
1001
|
});
|
|
1002
|
-
const res = name === "ask" ? await (await import("../../ask-
|
|
1002
|
+
const res = name === "ask" ? await (await import("../../ask-3LIAXR4S.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-QZDQVB57.js")).handleSearch(env, ctx, inner, tier, key);
|
|
1003
1003
|
return res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
|
|
1004
1004
|
});
|
|
1005
1005
|
if (out.ok && "accepted" in out) return new Response(null, { status: 202 });
|
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.41",
|
|
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",
|
|
@@ -25,7 +25,7 @@ import { evaluate as machineEvaluate, verdictNote } from "./verdict";
|
|
|
25
25
|
import { evaluateConditionSets, quantitiesIn, type ConditionVerdict } from "./conditions";
|
|
26
26
|
import { evaluateAggregation, type AggregationVerdict } from "./aggregation";
|
|
27
27
|
import { matchLicensedTopic, boundaryNoteText } from "./boundary";
|
|
28
|
-
import { answerQuality, qualityNote } from "./quality";
|
|
28
|
+
import { answerQuality, experimentalSourceLabels, qualityNote } from "./quality";
|
|
29
29
|
import { detectDraftIntent, prepareDraft } from "./drafts";
|
|
30
30
|
import { detectApiCallIntent, prepareApiCall } from "./apicalls";
|
|
31
31
|
import { memoryNote } from "./memories";
|
|
@@ -1115,9 +1115,16 @@ async function handleAsk(
|
|
|
1115
1115
|
await attachFigureImages(env, messages, usedHits, q.query);
|
|
1116
1116
|
if (userImage) {
|
|
1117
1117
|
// the user's own image rides on the question message — retrieval stays
|
|
1118
|
-
// text-driven; the answer model reads the image as question context
|
|
1118
|
+
// text-driven; the answer model reads the image as question context.
|
|
1119
|
+
// A markings/nameplate/certificate photo gets a TRANSCRIPTION note:
|
|
1120
|
+
// read the inscriptions verbatim first, then interpret from the
|
|
1121
|
+
// passages (the marking requirements are corpus content) — never
|
|
1122
|
+
// invent a marking that cannot be read.
|
|
1123
|
+
const wantsMarkings = /\b(mark(ing|ings)?|nameplate|label|inscription|engrav|sticker|plate)\b|certificat/i.test(q.query);
|
|
1119
1124
|
const last = messages[messages.length - 1];
|
|
1120
|
-
const note =
|
|
1125
|
+
const note = wantsMarkings
|
|
1126
|
+
? "\n\n(The user attached a photo with this question. First transcribe every inscription you can actually read in the image — names, model references, accuracy classes, numeric values with their units, certificate or approval numbers — quoting them verbatim. Then answer the question from the numbered passages, citing the requirement each interpretation rests on. If an inscription is unreadable, say so; never invent a marking.)"
|
|
1127
|
+
: "\n\n(The user attached an image with this question; interpret it directly when answering.)";
|
|
1121
1128
|
if (Array.isArray(last.content)) {
|
|
1122
1129
|
const textPart = last.content.find((p: any) => p.type === "text");
|
|
1123
1130
|
if (textPart) textPart.text += note;
|
|
@@ -1147,7 +1154,7 @@ async function handleAsk(
|
|
|
1147
1154
|
// retrieval, before a single token of the answer
|
|
1148
1155
|
send({ type: "read", read: readAs() });
|
|
1149
1156
|
const sourceQuality = answerQuality(cites.map((c: any) => c.quality));
|
|
1150
|
-
send({ type: "citations", citations: cites, context_applied: ctxApplied, ...(sourceQuality ? { source_quality: sourceQuality,
|
|
1157
|
+
send({ type: "citations", citations: cites, context_applied: ctxApplied, ...(sourceQuality ? { source_quality: sourceQuality, confidence_note: qualityNote(sourceQuality), ...(sourceQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(cites) } : {}) } : {}), ...(liveRecords ? { records: liveRecords } : {}), quota, });
|
|
1151
1158
|
let full = "";
|
|
1152
1159
|
try {
|
|
1153
1160
|
for await (const tok of sseTokens(stream)) {
|
|
@@ -1342,7 +1349,7 @@ async function handleAsk(
|
|
|
1342
1349
|
completionBlocks.push(...(await completeFigures(env.DB, answer, [...c2ns.blocks, ...completionBlocks], used)));
|
|
1343
1350
|
|
|
1344
1351
|
const jsonQuality = answerQuality(finalCites.map((c: any) => c.quality));
|
|
1345
|
-
const out = { answer, citations: finalCites, ...(jsonQuality ? { source_quality: jsonQuality,
|
|
1352
|
+
const out = { answer, citations: finalCites, ...(jsonQuality ? { source_quality: jsonQuality, confidence_note: qualityNote(jsonQuality), ...(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] : []), ...completionBlocks], context_applied: ctxApplied, ...(liveRecords ? { records: liveRecords } : {}) };
|
|
1346
1353
|
const cacheable = !contextual && !declaredCtx && !answer.includes(refusalAnswer()) && finalAnchors.violations.length === 0;
|
|
1347
1354
|
if (cacheable) {
|
|
1348
1355
|
const warmVec = (await warmEmbed) ?? null;
|
|
@@ -40,9 +40,30 @@ export function answerQuality(qualities: (SourceQuality | undefined)[]): SourceQ
|
|
|
40
40
|
return worst;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
/** The one-line posture the interface renders under the answer.
|
|
43
|
+
/** The one-line posture the interface renders under the answer. The
|
|
44
|
+
* OCR rung is the owner's 2026-09-26 wording, verbatim. */
|
|
44
45
|
export function qualityNote(q: SourceQuality): string {
|
|
45
|
-
if (q === "verified") return "
|
|
46
|
-
if (q === "curated") return "
|
|
47
|
-
return "Partly grounded in experimental
|
|
46
|
+
if (q === "verified") return "High confidence: this publication's requirements ride a machine-checkable data model.";
|
|
47
|
+
if (q === "curated") return "Established sources: Metanorma-edited documents, chunked at clause boundaries.";
|
|
48
|
+
return "WARNING: Partly grounded in experimental data source that was derived from OCR content. Please verify content against official publications.";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The citations standing on the OCR rung, named for the reader — the
|
|
52
|
+
* confidence line says WHICH sources are experimental, not just that
|
|
53
|
+
* some are. Producer-UUID anchors say nothing and are dropped; a cap
|
|
54
|
+
* keeps the line readable on citation-heavy answers. */
|
|
55
|
+
export function experimentalSourceLabels(
|
|
56
|
+
cites: { quality?: string; docidentifier?: string; doc_id?: string; clause_anchor?: string }[],
|
|
57
|
+
cap = 6,
|
|
58
|
+
): string[] {
|
|
59
|
+
const labels: string[] = [];
|
|
60
|
+
for (const c of cites) {
|
|
61
|
+
if (c.quality !== "ocr") continue;
|
|
62
|
+
const id = String(c.docidentifier || c.doc_id || "source");
|
|
63
|
+
const anchor = String(c.clause_anchor ?? "");
|
|
64
|
+
const garbage = /^[0-9a-f]{8}-[0-9a-f]{4}-/i.test(anchor) || (anchor.startsWith("_") && anchor.length > 12);
|
|
65
|
+
labels.push(garbage || !anchor || anchor === "overview" ? id : `${id} §${anchor}`);
|
|
66
|
+
if (labels.length >= cap) break;
|
|
67
|
+
}
|
|
68
|
+
return labels;
|
|
48
69
|
}
|