@konneal/engine 0.2.49 → 0.2.51

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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  handleAsk
3
- } from "./chunk-4KA34NMU.js";
3
+ } from "./chunk-HT2MDJ5S.js";
4
4
  import "./chunk-VVLNUHW2.js";
5
5
  import "./chunk-JWTIPQ4L.js";
6
6
  import "./chunk-A3QHHUN5.js";
@@ -2193,7 +2193,11 @@ async function handleAsk(env, ctx, req, tier, key) {
2193
2193
  telemetry(env, ctx, tier, "ask", null, true, (cached.value.answer ?? "").length, cached.value.query_hash, q.lang, "exact", telemetryMeta());
2194
2194
  const cctx = cached.value.context_applied ?? NO_CONTEXT;
2195
2195
  if (wantsStream) {
2196
- return sseResponse([{ type: "citations", citations: cached.value.citations ?? [], quota, context_applied: cctx }, { type: "token", v: cached.value.answer ?? "" }, { type: "done", model: cached.value.model ?? MODELS.member, query_hash: cached.value.query_hash, served_from: "cache", context_applied: cctx }], corsHeaders(req));
2196
+ return sseResponse([
2197
+ { type: "citations", citations: cached.value.citations ?? [], quota, context_applied: cctx, ...cached.value.source_quality ? { source_quality: cached.value.source_quality, confidence_note: cached.value.confidence_note ?? null, ...cached.value.experimental_sources ? { experimental_sources: cached.value.experimental_sources } : {}, ...cached.value.entailment ? { entailment: cached.value.entailment } : {} } : {} },
2198
+ { type: "token", v: cached.value.answer ?? "" },
2199
+ { type: "done", model: cached.value.model ?? MODELS.member, query_hash: cached.value.query_hash, served_from: "cache", context_applied: cctx }
2200
+ ], corsHeaders(req));
2197
2201
  }
2198
2202
  return json({ ...cached.value, cached: true, quota, context_applied: cctx });
2199
2203
  }
@@ -2702,6 +2706,21 @@ Answer account questions from these records ONLY: name the record when you use i
2702
2706
  });
2703
2707
  telemetry(env, ctx, tier, "ask", model, true, c2.text.length, queryHash, q.lang, void 0, telemetryMeta());
2704
2708
  const canonical = c2.text;
2709
+ let streamedEntailment = null;
2710
+ let streamedNote = "";
2711
+ if (THRESHOLDS.entailmentGate && sourceQuality && usedHits.length && !canonical.includes(refusalAnswer())) {
2712
+ const raced = await Promise.race([
2713
+ scoreFaithfulness(env.AI, roleModel(env, "grader"), canonical, usedHits.map((h) => h.text)),
2714
+ new Promise((r) => setTimeout(() => r(null), THRESHOLDS.entailmentBudgetMs))
2715
+ ]);
2716
+ if (raced) {
2717
+ const v = entailmentVerdict(raced.score, THRESHOLDS.entailmentSupportedFloor, THRESHOLDS.entailmentPartialFloor);
2718
+ streamedEntailment = { support: v.support, score: Math.round(raced.score * 100) / 100, ...raced.ungrounded_claims?.length ? { ungrounded: raced.ungrounded_claims.slice(0, 3) } : {} };
2719
+ streamedNote = v.note;
2720
+ if (v.support !== "supported") console.log("entailment(stream):", v.support, raced.score);
2721
+ send({ type: "confidence", source_quality: sourceQuality, confidence_note: streamedNote || qualityNote(sourceQuality), ...streamedEntailment ? { entailment: streamedEntailment } : {} });
2722
+ }
2723
+ }
2705
2724
  const streamedAnchors = checkQuoteAnchors(canonical, usedHits.map((h) => h.text));
2706
2725
  const streamedRetyped = tableRetyped(canonical, usedHits.some((h) => h.metadata.unit_id && h.metadata.block === "table"));
2707
2726
  const streamed = { total: streamedAnchors.total, violations: streamedRetyped ? ["table-retyped"] : streamedAnchors.violations };
@@ -2710,7 +2729,7 @@ Answer account questions from these records ONLY: name the record when you use i
2710
2729
  }
2711
2730
  if (streamed.violations.length === 0 && canonical.length > 0 && !contextual && !declaredCtx && !canonical.includes(refusalAnswer())) {
2712
2731
  ctx.waitUntil(
2713
- 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 }), { expirationTtl: LIMITS.cacheTtlSec })
2732
+ 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 })
2714
2733
  );
2715
2734
  }
2716
2735
  controller.close();
@@ -10,7 +10,7 @@ import {
10
10
  scoreFaithfulness,
11
11
  scoreJudge,
12
12
  standardForDocNumber
13
- } from "../../chunk-4KA34NMU.js";
13
+ } from "../../chunk-HT2MDJ5S.js";
14
14
  import {
15
15
  buildMessages,
16
16
  cfBlobs,
@@ -947,7 +947,7 @@ async function handleMcp(env, ctx, req, tier, key) {
947
947
  // stream:false forces the JSON lane (anon defaults to SSE)
948
948
  body: JSON.stringify({ ...args, stream: false })
949
949
  });
950
- const res = name === "ask" ? await (await import("../../ask-OH5KPHZA.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-KNB2S2PS.js")).handleSearch(env, ctx, inner, tier, key);
950
+ const res = name === "ask" ? await (await import("../../ask-FZA3ZFVB.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-KNB2S2PS.js")).handleSearch(env, ctx, inner, tier, key);
951
951
  return res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
952
952
  });
953
953
  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.49",
30
+ "version": "0.2.51",
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",
@@ -14,8 +14,10 @@ info:
14
14
  administrator; signed-in members obtain a higher allowance together
15
15
  with conversation synchronisation, project memory and research mode.
16
16
  servers:
17
+ - url: https://www.ommisa.org
18
+ description: Production (the canonical door)
17
19
  - url: https://ai.oimlsmart.org
18
- description: Production
20
+ description: The institutional origin — a permanent, method-preserving redirect to the canonical door
19
21
  tags:
20
22
  - name: Ask
21
23
  description: Ask a question and receive a citation-grounded answer.
@@ -407,7 +407,11 @@ async function handleAsk(
407
407
  const cctx = cached.value.context_applied ?? NO_CONTEXT;
408
408
  if (wantsStream) {
409
409
  // a cache hit must still speak SSE — the chat client parses a stream
410
- return sseResponse([{ type: "citations", citations: cached.value.citations ?? [], quota, context_applied: cctx }, { type: "token", v: cached.value.answer ?? "" }, { type: "done", model: cached.value.model ?? MODELS.member, query_hash: cached.value.query_hash, served_from: "cache", context_applied: cctx }], corsHeaders(req));
410
+ return sseResponse([
411
+ { type: "citations", citations: cached.value.citations ?? [], quota, context_applied: cctx, ...(cached.value.source_quality ? { source_quality: cached.value.source_quality, confidence_note: cached.value.confidence_note ?? null, ...(cached.value.experimental_sources ? { experimental_sources: cached.value.experimental_sources } : {}), ...(cached.value.entailment ? { entailment: cached.value.entailment } : {}) } : {}) },
412
+ { type: "token", v: cached.value.answer ?? "" },
413
+ { type: "done", model: cached.value.model ?? MODELS.member, query_hash: cached.value.query_hash, served_from: "cache", context_applied: cctx },
414
+ ], corsHeaders(req));
411
415
  }
412
416
  return json({ ...cached.value, cached: true, quota, context_applied: cctx });
413
417
  }
@@ -1140,6 +1144,27 @@ async function handleAsk(
1140
1144
  passages: usedHits.slice(0, 8).map((h: Hit) => ({ d: h.metadata.docidentifier ?? "", a: h.metadata.clause_anchor ?? "", t: (h.text ?? "").slice(0, (h.metadata as any).block === "table" ? 1400 : 600), b: (h.metadata as any).block === "table" || undefined, ...((h.metadata as any).table_selection ? { s: (h.metadata as any).table_selection } : {}) })) });
1141
1145
  telemetry(env, ctx, tier, "ask", model, true, c2.text.length, queryHash, q.lang, undefined, telemetryMeta());
1142
1146
  const canonical = c2.text;
1147
+
1148
+ // the entailment gate, streaming shape (TODO.new-era/10): the
1149
+ // measurement runs AFTER done — the chips, follow-ups and evidence
1150
+ // never wait on the grader; a final confidence event refreshes the
1151
+ // note when the measurement lands. Budgeted and fail-open like the
1152
+ // JSON path's gate.
1153
+ let streamedEntailment: { support: string; score: number; ungrounded?: string[] } | null = null;
1154
+ let streamedNote = "";
1155
+ if (THRESHOLDS.entailmentGate && sourceQuality && usedHits.length && !canonical.includes(refusalAnswer())) {
1156
+ const raced = await Promise.race([
1157
+ scoreFaithfulness(env.AI, roleModel(env, "grader"), canonical, usedHits.map((h: Hit) => h.text)),
1158
+ new Promise<null>((r) => setTimeout(() => r(null), THRESHOLDS.entailmentBudgetMs)),
1159
+ ]);
1160
+ if (raced) {
1161
+ const v = entailmentVerdict(raced.score, THRESHOLDS.entailmentSupportedFloor, THRESHOLDS.entailmentPartialFloor);
1162
+ streamedEntailment = { support: v.support, score: Math.round(raced.score * 100) / 100, ...(raced.ungrounded_claims?.length ? { ungrounded: raced.ungrounded_claims.slice(0, 3) } : {}) };
1163
+ streamedNote = v.note;
1164
+ if (v.support !== "supported") console.log("entailment(stream):", v.support, raced.score);
1165
+ send({ type: "confidence", source_quality: sourceQuality, confidence_note: streamedNote || qualityNote(sourceQuality), ...(streamedEntailment ? { entailment: streamedEntailment } : {}) });
1166
+ }
1167
+ }
1143
1168
  // streamed answers can't be regenerated mid-flight; enforcement
1144
1169
  // is that an unverified answer is never served from cache again
1145
1170
  const streamedAnchors = checkQuoteAnchors(canonical, usedHits.map((h: Hit) => h.text));
@@ -1150,7 +1175,7 @@ async function handleAsk(
1150
1175
  }
1151
1176
  if (streamed.violations.length === 0 && canonical.length > 0 && !contextual && !declaredCtx && !canonical.includes(refusalAnswer())) {
1152
1177
  ctx.waitUntil(
1153
- 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 }), { expirationTtl: LIMITS.cacheTtlSec }),
1178
+ 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 }),
1154
1179
  );
1155
1180
  }
1156
1181
  controller.close();