@konneal/engine 0.2.16 → 0.2.17

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-XHJI73N2.js";
3
+ } from "./chunk-DRQ37UGZ.js";
4
4
  import "./chunk-7UT76RQO.js";
5
5
  import "./chunk-EFQALN2Z.js";
6
6
  import "./chunk-DBBGOOMZ.js";
@@ -931,12 +931,31 @@ function cellValue(row, cols, col) {
931
931
  const raw = row[idx] ?? "";
932
932
  return num2(raw) ?? String(raw).trim();
933
933
  }
934
- function pickTable(nodes, queryLower) {
934
+ function classValueExists(rows, cols, token) {
935
+ const cc = classColumn(cols);
936
+ if (!cc) return false;
937
+ const idx = cols.indexOf(cc);
938
+ return rows.some((r) => String(r[idx] ?? "").trim().toLowerCase() === token);
939
+ }
940
+ function statedUnits(query) {
941
+ const out = /* @__PURE__ */ new Set();
942
+ const re = new RegExp(`(${NUM2})\\s*([%\xB0a-zA-Z][a-zA-Z/.%\xB0]*\\b)`, "g");
943
+ for (const m of query.matchAll(re)) {
944
+ if (m[2]) out.add(m[2].replace("\u2062", "").trim());
945
+ }
946
+ return out;
947
+ }
948
+ function pickTable(nodes, query) {
949
+ const queryLower = query.toLowerCase();
950
+ const stated = statedUnits(query);
951
+ const cToken = classToken(query);
935
952
  let best = null;
936
953
  for (const n of nodes) {
937
954
  const c = n.content ?? {};
938
955
  const payload = c.payload ?? {};
939
956
  if (!Array.isArray(payload.rows) || !payload.rows.length) continue;
957
+ const cols = Array.isArray(payload.columns) ? payload.columns : [];
958
+ const rows = (Array.isArray(payload.rows) ? payload.rows : []).filter((r) => Array.isArray(r));
940
959
  let score = 0;
941
960
  for (const t of tokens(n.node_id.replace("/table/", ""))) {
942
961
  if (t.length >= 3 && queryLower.includes(t)) score += 2;
@@ -944,6 +963,8 @@ function pickTable(nodes, queryLower) {
944
963
  for (const w of String(c.name ?? "").toLowerCase().split(/[^a-z0-9.]+/)) {
945
964
  if (w.length >= 4 && queryLower.includes(w)) score += 1;
946
965
  }
966
+ if (intervalPairs(cols).some((p) => p.low.unit && stated.has(p.low.unit))) score += 3;
967
+ if (cToken && (classAsColumn(cols, cToken) || classValueExists(rows, cols, cToken))) score += 2;
947
968
  if (!best || score > best.score) best = { node: n, score };
948
969
  }
949
970
  if (best && best.score > 0) return best.node;
@@ -953,7 +974,7 @@ function evaluateAggregation(nodes, query) {
953
974
  const qLower = query.toLowerCase();
954
975
  const operation = /\bhow many\b|\bnumber of\b/.test(qLower) ? "count" : /\b(minimum|smallest|shortest|lowest|least)\b/.test(qLower) ? "min" : /\b(maximum|largest|longest|highest|greatest)\b/.test(qLower) ? "max" : "lookup";
955
976
  if (!nodes.length) return null;
956
- const node = pickTable(nodes, qLower);
977
+ const node = pickTable(nodes, query);
957
978
  if (!node) return null;
958
979
  const content = node.content && typeof node.content === "object" ? node.content : {};
959
980
  const payload = content.payload ?? {};
@@ -7,7 +7,7 @@ import {
7
7
  handleMemories,
8
8
  scoreJudge,
9
9
  standardForDocNumber
10
- } from "../../chunk-XHJI73N2.js";
10
+ } from "../../chunk-DRQ37UGZ.js";
11
11
  import {
12
12
  buildMessages,
13
13
  citations,
@@ -979,7 +979,7 @@ async function handleMcp(env, ctx, req, tier, key) {
979
979
  // stream:false forces the JSON lane (anon defaults to SSE)
980
980
  body: JSON.stringify({ ...args, stream: false })
981
981
  });
982
- const res = name === "ask" ? await (await import("../../ask-MMJHOZ6Y.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-RFKT7ZZY.js")).handleSearch(env, ctx, inner, tier, key);
982
+ const res = name === "ask" ? await (await import("../../ask-PKKNMLLM.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-RFKT7ZZY.js")).handleSearch(env, ctx, inner, tier, key);
983
983
  return res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
984
984
  });
985
985
  if (out.ok && "accepted" in out) return new Response(null, { status: 202 });
package/package.json CHANGED
@@ -34,7 +34,7 @@
34
34
  "@oimlsmart/oiml-pubid": "^1.2.1"
35
35
  },
36
36
  "dependencies": {},
37
- "version": "0.2.16",
37
+ "version": "0.2.17",
38
38
  "description": "The Konneal engine: the publisher-agnostic build pipeline and API plane for standards intelligence (retrieval, answer contract, verdicts, evaluation).",
39
39
  "license": "BSD-3-Clause",
40
40
  "type": "module",
@@ -140,12 +140,35 @@ function cellValue(row: string[], cols: Column[], col: Column): number | string
140
140
  return num(raw) ?? String(raw).trim();
141
141
  }
142
142
 
143
- function pickTable(nodes: { node_id: string; content: any }[], queryLower: string): { node_id: string; content: any } | null {
143
+ /** The named class exists as a row VALUE of the table's class column
144
+ * (mpe_tiers' accuracy_class A/B/C/D rows). */
145
+ function classValueExists(rows: string[][], cols: Column[], token: string): boolean {
146
+ const cc = classColumn(cols);
147
+ if (!cc) return false;
148
+ const idx = cols.indexOf(cc);
149
+ return rows.some((r) => String(r[idx] ?? "").trim().toLowerCase() === token);
150
+ }
151
+
152
+ function statedUnits(query: string): Set<string> {
153
+ const out = new Set<string>();
154
+ const re = new RegExp(`(${NUM})\\s*([%°a-zA-Z][a-zA-Z/.%°]*\\b)`,"g");
155
+ for (const m of query.matchAll(re)) {
156
+ if (m[2]) out.add(m[2].replace("\u2062", "").trim());
157
+ }
158
+ return out;
159
+ }
160
+
161
+ function pickTable(nodes: { node_id: string; content: any }[], query: string): { node_id: string; content: any } | null {
162
+ const queryLower = query.toLowerCase();
163
+ const stated = statedUnits(query);
164
+ const cToken = classToken(query);
144
165
  let best: { node: { node_id: string; content: any }; score: number } | null = null;
145
166
  for (const n of nodes) {
146
167
  const c = n.content ?? {};
147
168
  const payload = (c.payload ?? {}) as { columns?: Column[]; rows?: unknown[] };
148
169
  if (!Array.isArray(payload.rows) || !payload.rows.length) continue;
170
+ const cols = (Array.isArray(payload.columns) ? payload.columns : []) as Column[];
171
+ const rows = (Array.isArray(payload.rows) ? payload.rows : []).filter((r) => Array.isArray(r)) as string[][];
149
172
  let score = 0;
150
173
  for (const t of tokens(n.node_id.replace("/table/", ""))) {
151
174
  if (t.length >= 3 && queryLower.includes(t)) score += 2;
@@ -153,6 +176,11 @@ function pickTable(nodes: { node_id: string; content: any }[], queryLower: strin
153
176
  for (const w of String(c.name ?? "").toLowerCase().split(/[^a-z0-9.]+/)) {
154
177
  if (w.length >= 4 && queryLower.includes(w)) score += 1;
155
178
  }
179
+ // the question's stated unit existing as this table's interval unit,
180
+ // and the named class resolving here, are the strongest signals —
181
+ // a table without either cannot hold the lookup
182
+ if (intervalPairs(cols).some((p) => p.low.unit && stated.has(p.low.unit))) score += 3;
183
+ if (cToken && (classAsColumn(cols, cToken) || classValueExists(rows, cols, cToken))) score += 2;
156
184
  if (!best || score > best.score) best = { node: n, score };
157
185
  }
158
186
  // an un-scored pick across several tables would be a guess: refuse
@@ -177,7 +205,7 @@ export function evaluateAggregation(
177
205
  ? "max"
178
206
  : "lookup";
179
207
  if (!nodes.length) return null;
180
- const node = pickTable(nodes, qLower);
208
+ const node = pickTable(nodes, query);
181
209
  if (!node) return null;
182
210
  const content = (node.content && typeof node.content === "object" ? node.content : {}) as Record<string, any>;
183
211
  const payload = (content.payload ?? {}) as { columns?: Column[]; rows?: unknown[] };