@konneal/engine 0.2.42 → 0.2.44

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-ZAAKM54K.js";
3
+ } from "./chunk-HDUSO5S5.js";
4
4
  import "./chunk-N2UOENDY.js";
5
5
  import "./chunk-R2V3X6SQ.js";
6
6
  import "./chunk-A3QHHUN5.js";
@@ -16,6 +16,18 @@ export declare function isRegisterShaped(query: string): boolean;
16
16
  * numbers ("190", "HM14H1"). Upper-cased tokens match case-insensitively
17
17
  * in SQL LIKE. */
18
18
  export declare function registerTokens(query: string): string[];
19
+ /** The register query for a token set. Numeric tokens (a model number
20
+ * like "190") must match as a STANDALONE value — `LIKE '%190%'` also
21
+ * catches "XK3190", which the live Utilcell probe demonstrated — so a
22
+ * number matches the exact model, or as a delimiter-separated word
23
+ * (hyphens and punctuation normalize to spaces). Word tokens keep the
24
+ * substring LIKE (names and model words do not overmatch the way
25
+ * numbers do). Each token takes its own numbered placeholder,
26
+ * referenced three times (holder, model, number). */
27
+ export declare function buildRegisterQuery(tokens: string[]): {
28
+ sql: string;
29
+ params: string[];
30
+ };
19
31
  export declare function searchRegister(db: any, query: string): Promise<{
20
32
  rows: RegisterRow[];
21
33
  tokens: string[];
@@ -1810,14 +1810,32 @@ function registerTokens(query) {
1810
1810
  }
1811
1811
  return tokens2.slice(0, 6);
1812
1812
  }
1813
+ function buildRegisterQuery(tokens2) {
1814
+ const params = [];
1815
+ const clauses = tokens2.map((t) => {
1816
+ if (/^\d+$/.test(t)) {
1817
+ const padded = `% ${t.toLowerCase()} %`;
1818
+ params.push(t, t, padded);
1819
+ const n1 = params.length - 2;
1820
+ const n2 = params.length;
1821
+ return `(model = ?${n1} OR num = ?${n1} OR (' ' || REPLACE(REPLACE(REPLACE(LOWER(model), '-', ' '), ',', ' '), '.', ' ') || ' ') LIKE ?${n2})`;
1822
+ }
1823
+ params.push(`%${t}%`);
1824
+ const n = params.length;
1825
+ return `(holder LIKE ?${n} OR model LIKE ?${n} OR num LIKE ?${n})`;
1826
+ });
1827
+ return {
1828
+ sql: `SELECT num, family, holder, model, year, status FROM certificates WHERE ${clauses.join(" OR ")} LIMIT 6`,
1829
+ params
1830
+ };
1831
+ }
1813
1832
  async function searchRegister(db, query) {
1814
1833
  if (!isRegisterShaped(query)) return null;
1815
1834
  const tokens2 = registerTokens(query);
1816
1835
  if (!tokens2.length) return null;
1817
- const clauses = tokens2.map(() => "(holder LIKE ?1 OR model LIKE ?1 OR num LIKE ?1)").join(" OR ");
1818
- const params = tokens2.map((t) => `%${t}%`);
1836
+ const { sql, params } = buildRegisterQuery(tokens2);
1819
1837
  try {
1820
- const res = await db.prepare(`SELECT num, family, holder, model, year, status FROM certificates WHERE ${clauses} LIMIT 6`).bind(...params).all();
1838
+ const res = await db.prepare(sql).bind(...params).all();
1821
1839
  return { rows: res.results ?? [], tokens: tokens2 };
1822
1840
  } catch {
1823
1841
  return { rows: [], tokens: tokens2 };
@@ -9,7 +9,7 @@ import {
9
9
  modelGroundingBlock,
10
10
  scoreJudge,
11
11
  standardForDocNumber
12
- } from "../../chunk-ZAAKM54K.js";
12
+ } from "../../chunk-HDUSO5S5.js";
13
13
  import {
14
14
  buildMessages,
15
15
  citations,
@@ -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-LFU3M2JA.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-QZDQVB57.js")).handleSearch(env, ctx, inner, tier, key);
1002
+ const res = name === "ask" ? await (await import("../../ask-JOX2D7KH.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.42",
30
+ "version": "0.2.44",
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",
@@ -48,17 +48,45 @@ export function registerTokens(query: string): string[] {
48
48
  return tokens.slice(0, 6);
49
49
  }
50
50
 
51
+ /** The register query for a token set. Numeric tokens (a model number
52
+ * like "190") must match as a STANDALONE value — `LIKE '%190%'` also
53
+ * catches "XK3190", which the live Utilcell probe demonstrated — so a
54
+ * number matches the exact model, or as a delimiter-separated word
55
+ * (hyphens and punctuation normalize to spaces). Word tokens keep the
56
+ * substring LIKE (names and model words do not overmatch the way
57
+ * numbers do). Each token takes its own numbered placeholder,
58
+ * referenced three times (holder, model, number). */
59
+ export function buildRegisterQuery(tokens: string[]): { sql: string; params: string[] } {
60
+ const params: string[] = [];
61
+ const clauses = tokens.map((t) => {
62
+ if (/^\d+$/.test(t)) {
63
+ // a number matches as a STANDALONE value: the exact model or
64
+ // certificate number, or a delimiter-separated word (hyphens and
65
+ // punctuation normalize to spaces) — never a substring ("190"
66
+ // must not catch "XK3190")
67
+ const padded = `% ${t.toLowerCase()} %`;
68
+ params.push(t, t, padded);
69
+ const n1 = params.length - 2;
70
+ const n2 = params.length;
71
+ return `(model = ?${n1} OR num = ?${n1} OR (' ' || REPLACE(REPLACE(REPLACE(LOWER(model), '-', ' '), ',', ' '), '.', ' ') || ' ') LIKE ?${n2})`;
72
+ }
73
+ params.push(`%${t}%`);
74
+ const n = params.length;
75
+ return `(holder LIKE ?${n} OR model LIKE ?${n} OR num LIKE ?${n})`;
76
+ });
77
+ return {
78
+ sql: `SELECT num, family, holder, model, year, status FROM certificates WHERE ${clauses.join(" OR ")} LIMIT 6`,
79
+ params,
80
+ };
81
+ }
82
+
51
83
  export async function searchRegister(db: any, query: string): Promise<{ rows: RegisterRow[]; tokens: string[] } | null> {
52
84
  if (!isRegisterShaped(query)) return null;
53
85
  const tokens = registerTokens(query);
54
86
  if (!tokens.length) return null;
55
- const clauses = tokens.map(() => "(holder LIKE ?1 OR model LIKE ?1 OR num LIKE ?1)").join(" OR ");
56
- const params = tokens.map((t) => `%${t}%`);
87
+ const { sql, params } = buildRegisterQuery(tokens);
57
88
  try {
58
- const res = await db
59
- .prepare(`SELECT num, family, holder, model, year, status FROM certificates WHERE ${clauses} LIMIT 6`)
60
- .bind(...params)
61
- .all();
89
+ const res = await db.prepare(sql).bind(...params).all();
62
90
  return { rows: (res.results ?? []) as RegisterRow[], tokens };
63
91
  } catch {
64
92
  // a missing table or a D1 hiccup degrades to no-note honestly