@konneal/engine 0.2.71 → 0.2.72

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,12 +1,12 @@
1
1
  import {
2
2
  handleAsk
3
- } from "./chunk-EOQVQBS6.js";
3
+ } from "./chunk-UW5M2AXR.js";
4
4
  import "./chunk-TPV5GPY2.js";
5
5
  import "./chunk-SPKPH54J.js";
6
6
  import "./chunk-A3QHHUN5.js";
7
7
  import "./chunk-LVZTWUVJ.js";
8
8
  import "./chunk-2PCUAJJO.js";
9
- import "./chunk-VGVTIPFW.js";
9
+ import "./chunk-3IRX4B7Q.js";
10
10
  import "./chunk-3FYJM7LH.js";
11
11
  export {
12
12
  handleAsk
@@ -6,7 +6,7 @@ import {
6
6
  registerNote,
7
7
  registerTokens,
8
8
  searchRegister
9
- } from "./chunk-VGVTIPFW.js";
9
+ } from "./chunk-3IRX4B7Q.js";
10
10
  import "./chunk-3FYJM7LH.js";
11
11
  export {
12
12
  buildRegisterQuery,
@@ -121,7 +121,7 @@ function registerNote(rows) {
121
121
  ].join("\n");
122
122
  }
123
123
  function certificateLinks(rows) {
124
- const links = rows.filter((r) => r.pdf_key).map((r) => `- ${r.num}: https://www.oimlsmart.org/cert-pdf/${r.pdf_key}`);
124
+ const links = rows.filter((r) => r.pdf_key).map((r) => `- ${r.num}: https://www.ommisa.org/cert-pdf/${r.pdf_key}`);
125
125
  return links.length ? `The certificates' documents:
126
126
  ${links.join("\n")}` : "";
127
127
  }
@@ -68,7 +68,7 @@ import {
68
68
  certificateLinks,
69
69
  registerNote,
70
70
  searchRegister
71
- } from "./chunk-VGVTIPFW.js";
71
+ } from "./chunk-3IRX4B7Q.js";
72
72
  import {
73
73
  P
74
74
  } from "./chunk-3FYJM7LH.js";
@@ -1892,7 +1892,7 @@ async function runTool(db, call) {
1892
1892
  if (call.name !== "register_search") return null;
1893
1893
  const query = String(call.args?.query ?? "").trim().slice(0, 160);
1894
1894
  if (!query) return null;
1895
- const { searchRegister: searchRegister2, registerNote: registerNote2 } = await import("./certificates-DNRUOYRF.js");
1895
+ const { searchRegister: searchRegister2, registerNote: registerNote2 } = await import("./certificates-EMHFAUWC.js");
1896
1896
  const reg = await searchRegister2(db, query, true);
1897
1897
  const output = reg?.rows?.length ? registerNote2(reg.rows) : `No certificate was found for "${query}" in the certificates database (the register snapshot). State this as the search's result, with the searched string visible.`;
1898
1898
  return { name: call.name, query, output };
@@ -1929,17 +1929,59 @@ var ACTION_STEMS = [
1929
1929
  "announc",
1930
1930
  "download"
1931
1931
  ];
1932
+ var STOP_WORDS = /* @__PURE__ */ new Set([
1933
+ "which",
1934
+ "what",
1935
+ "where",
1936
+ "when",
1937
+ "how",
1938
+ "why",
1939
+ "who",
1940
+ "does",
1941
+ "did",
1942
+ "can",
1943
+ "the",
1944
+ "and",
1945
+ "for",
1946
+ "with",
1947
+ "that",
1948
+ "this",
1949
+ "are",
1950
+ "was",
1951
+ "were",
1952
+ "has",
1953
+ "have",
1954
+ "had",
1955
+ "not",
1956
+ "but",
1957
+ "all",
1958
+ "any",
1959
+ "platform",
1960
+ "operation",
1961
+ "operations",
1962
+ "endpoint",
1963
+ "endpoints",
1964
+ "api"
1965
+ ]);
1966
+ function anchorWords(anchor) {
1967
+ return anchor.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
1968
+ }
1969
+ var singular = (w) => w.length > 3 && w.endsWith("s") ? w.slice(0, -1) : w;
1932
1970
  function matchOperations(query, rows) {
1933
1971
  const q = query.toLowerCase();
1934
1972
  const stems = ACTION_STEMS.filter((s) => q.includes(s));
1935
- if (!stems.length) return [];
1973
+ const objects = query.toLowerCase().split(/[^a-z0-9]+/).filter((w) => w.length > 2 && !STOP_WORDS.has(w)).map(singular);
1936
1974
  const scored = [];
1937
1975
  for (const r of rows) {
1938
1976
  const hay = `${r.anchor} ${r.text}`.toLowerCase();
1939
- const score = stems.filter((s) => hay.includes(s)).length;
1940
- if (score > 0) scored.push({ ...r, score });
1977
+ const verbScore = stems.filter((s) => hay.includes(s)).length * 3;
1978
+ const words = anchorWords(r.anchor).map(singular);
1979
+ const objectScore = objects.filter((o) => words.includes(o)).length * 10;
1980
+ if (objectScore + verbScore > 0) scored.push({ ...r, score: objectScore + verbScore, objectScore });
1941
1981
  }
1942
- return scored.sort((a, b) => b.score - a.score).slice(0, 4);
1982
+ const named = scored.filter((s) => s.objectScore > 0);
1983
+ const pool = named.length ? named : scored;
1984
+ return pool.sort((a, b) => b.score - a.score).slice(0, 4);
1943
1985
  }
1944
1986
  function catalogNote(anchors) {
1945
1987
  if (!anchors.length) return "";
@@ -1949,12 +1991,12 @@ ${anchors.map((a) => `- ${a}`).join("\n")}`;
1949
1991
  async function operationsCatalogNote(db, query) {
1950
1992
  if (!isOperationIntent(query)) return void 0;
1951
1993
  try {
1952
- const rows = (await db.prepare("SELECT clause_anchor AS anchor, substr(text, 1, 220) AS text FROM chunks WHERE corpus = 'smart-ops' AND clause_anchor IS NOT NULL ORDER BY clause_anchor").all()).results ?? [];
1994
+ const rows = (await db.prepare("SELECT clause_anchor AS anchor, substr(text, 1, 300) AS text FROM chunks WHERE corpus = 'smart-ops' AND clause_anchor IS NOT NULL ORDER BY clause_anchor").all()).results ?? [];
1953
1995
  const opRows = rows.map((r) => ({ anchor: String(r.anchor ?? ""), text: String(r.text ?? "") })).filter((r) => r.anchor);
1954
1996
  const matched = matchOperations(query, opRows);
1955
1997
  const parts = [];
1956
1998
  if (matched.length) {
1957
- parts.push(`Operations whose description matches the question's action (AUTHORITATIVE \u2014 if one matches, the answer MUST name it and cite its line; never answer that the information is missing):
1999
+ parts.push(`Operations whose name or description matches the question (AUTHORITATIVE \u2014 if one matches, the answer MUST name it and cite its line; never answer that the information is missing):
1958
2000
  ${matched.map((m) => `- ${m.text}`).join("\n")}`);
1959
2001
  }
1960
2002
  parts.push(catalogNote(opRows.map((r) => r.anchor)));
@@ -1,4 +1,8 @@
1
1
  export declare function isOperationIntent(query: string): boolean;
2
+ /** camelCase/snake anchors meet the question's words: "updates an
3
+ * entity record" must reach putEntityRecord even when its description
4
+ * words the action differently ("replaces the stored…"). */
5
+ export declare function anchorWords(anchor: string): string[];
2
6
  export declare function matchOperations(query: string, rows: {
3
7
  anchor: string;
4
8
  text: string;
@@ -6,7 +6,7 @@ import {
6
6
  modelGroundingBlock,
7
7
  scoreFaithfulness,
8
8
  scoreJudge
9
- } from "../../chunk-EOQVQBS6.js";
9
+ } from "../../chunk-UW5M2AXR.js";
10
10
  import {
11
11
  handleSearch
12
12
  } from "../../chunk-FLNX4O7C.js";
@@ -63,7 +63,7 @@ import {
63
63
  sha256Hex,
64
64
  today
65
65
  } from "../../chunk-2PCUAJJO.js";
66
- import "../../chunk-VGVTIPFW.js";
66
+ import "../../chunk-3IRX4B7Q.js";
67
67
  import {
68
68
  P,
69
69
  setProfile
@@ -959,7 +959,7 @@ async function handleMcp(env, ctx, req, tier, key) {
959
959
  // stream:false forces the JSON lane (anon defaults to SSE)
960
960
  body: JSON.stringify({ ...args, stream: false })
961
961
  });
962
- const res = name === "ask" ? await (await import("../../ask-OUNG3JIC.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-PBOODCMQ.js")).handleSearch(env, ctx, inner, tier, key);
962
+ const res = name === "ask" ? await (await import("../../ask-UOTYZ5DC.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-PBOODCMQ.js")).handleSearch(env, ctx, inner, tier, key);
963
963
  return res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
964
964
  });
965
965
  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.71",
30
+ "version": "0.2.72",
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",
@@ -134,7 +134,7 @@ export function registerNote(rows: RegisterRow[]): string {
134
134
  * is in the R2 plane (TODO 7) — the user gets the document, not just
135
135
  * the fact. */
136
136
  export function certificateLinks(rows: RegisterRow[]): string {
137
- const links = rows.filter((r) => r.pdf_key).map((r) => `- ${r.num}: https://www.oimlsmart.org/cert-pdf/${r.pdf_key}`);
137
+ const links = rows.filter((r) => r.pdf_key).map((r) => `- ${r.num}: https://www.ommisa.org/cert-pdf/${r.pdf_key}`);
138
138
  return links.length ? `The certificates' documents:\n${links.join("\n")}` : "";
139
139
  }
140
140
 
@@ -1,10 +1,11 @@
1
1
  // The operations catalog lane (TODO.new-era/6's platform surface): the
2
2
  // smart-ops corpus is SMALL (169 operations) and name-addressable. An
3
- // operation-intent question gets (1) the operations whose description
4
- // matches the question's action stems — with their full lines, and (2)
5
- // the complete name index. The note is AUTHORITATIVE: the model must
6
- // name the operation from it, never answer from the passages' silence.
7
- // Pure composition lives here; the D1 call is a thin wrapper.
3
+ // operation-intent question gets (1) the operations whose NAME carries
4
+ // the question's object words and whose description carries its action
5
+ // stems — with their full lines, and (2) the complete name index. The
6
+ // note is AUTHORITATIVE: the model must name the operation from it,
7
+ // never answer from the passages' silence. Pure composition lives
8
+ // here; the D1 call is a thin wrapper.
8
9
 
9
10
  export function isOperationIntent(query: string): boolean {
10
11
  return /\b(operations?|endpoints?)\b/i.test(query);
@@ -18,17 +19,48 @@ const ACTION_STEMS = [
18
19
  "confirm", "approv", "declin", "decide", "revok", "grant", "notify", "advanc", "announc", "download",
19
20
  ];
20
21
 
22
+ const STOP_WORDS = new Set([
23
+ "which", "what", "where", "when", "how", "why", "who", "does", "did", "can", "the", "and", "for",
24
+ "with", "that", "this", "are", "was", "were", "has", "have", "had", "not", "but", "all", "any",
25
+ "platform", "operation", "operations", "endpoint", "endpoints", "api",
26
+ ]);
27
+
28
+ /** camelCase/snake anchors meet the question's words: "updates an
29
+ * entity record" must reach putEntityRecord even when its description
30
+ * words the action differently ("replaces the stored…"). */
31
+ export function anchorWords(anchor: string): string[] {
32
+ return anchor
33
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
34
+ .toLowerCase()
35
+ .split(/[^a-z0-9]+/)
36
+ .filter(Boolean);
37
+ }
38
+
39
+ const singular = (w: string) => (w.length > 3 && w.endsWith("s") ? w.slice(0, -1) : w);
40
+
21
41
  export function matchOperations(query: string, rows: { anchor: string; text: string }[]): { anchor: string; text: string }[] {
22
42
  const q = query.toLowerCase();
23
43
  const stems = ACTION_STEMS.filter((s) => q.includes(s));
24
- if (!stems.length) return [];
25
- const scored: { anchor: string; text: string; score: number }[] = [];
44
+ const objects = query
45
+ .toLowerCase()
46
+ .split(/[^a-z0-9]+/)
47
+ .filter((w) => w.length > 2 && !STOP_WORDS.has(w))
48
+ .map(singular);
49
+ const scored: { anchor: string; text: string; score: number; objectScore: number }[] = [];
26
50
  for (const r of rows) {
27
51
  const hay = `${r.anchor} ${r.text}`.toLowerCase();
28
- const score = stems.filter((s) => hay.includes(s)).length;
29
- if (score > 0) scored.push({ ...r, score });
52
+ const verbScore = stems.filter((s) => hay.includes(s)).length * 3;
53
+ const words = anchorWords(r.anchor).map(singular);
54
+ const objectScore = objects.filter((o) => words.includes(o)).length * 10;
55
+ if (objectScore + verbScore > 0) scored.push({ ...r, score: objectScore + verbScore, objectScore });
30
56
  }
31
- return scored.sort((a, b) => b.score - a.score).slice(0, 4);
57
+ // A question that names its object ("entity record") has found its
58
+ // target by name — verb-only mentions are the noise that displaced
59
+ // the answer with an unrelated sibling (the 2026-09-29 "blob upload"
60
+ // answers).
61
+ const named = scored.filter((s) => s.objectScore > 0);
62
+ const pool = named.length ? named : scored;
63
+ return pool.sort((a, b) => b.score - a.score).slice(0, 4);
32
64
  }
33
65
 
34
66
  export function catalogNote(anchors: string[]): string {
@@ -39,12 +71,12 @@ export function catalogNote(anchors: string[]): string {
39
71
  export async function operationsCatalogNote(db: any, query: string): Promise<string | undefined> {
40
72
  if (!isOperationIntent(query)) return undefined;
41
73
  try {
42
- const rows = (await db.prepare("SELECT clause_anchor AS anchor, substr(text, 1, 220) AS text FROM chunks WHERE corpus = 'smart-ops' AND clause_anchor IS NOT NULL ORDER BY clause_anchor").all()).results ?? [];
74
+ const rows = (await db.prepare("SELECT clause_anchor AS anchor, substr(text, 1, 300) AS text FROM chunks WHERE corpus = 'smart-ops' AND clause_anchor IS NOT NULL ORDER BY clause_anchor").all()).results ?? [];
43
75
  const opRows = (rows as any[]).map((r) => ({ anchor: String(r.anchor ?? ""), text: String(r.text ?? "") })).filter((r) => r.anchor);
44
76
  const matched = matchOperations(query, opRows);
45
77
  const parts: string[] = [];
46
78
  if (matched.length) {
47
- parts.push(`Operations whose description matches the question's action (AUTHORITATIVE — if one matches, the answer MUST name it and cite its line; never answer that the information is missing):\n${matched.map((m) => `- ${m.text}`).join("\n")}`);
79
+ parts.push(`Operations whose name or description matches the question (AUTHORITATIVE — if one matches, the answer MUST name it and cite its line; never answer that the information is missing):\n${matched.map((m) => `- ${m.text}`).join("\n")}`);
48
80
  }
49
81
  parts.push(catalogNote(opRows.map((r) => r.anchor)));
50
82
  return parts.filter(Boolean).join("\n\n") || undefined;