@konneal/engine 0.2.136 → 0.2.138

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,10 +1,6 @@
1
1
  import {
2
- embed,
3
- hasLane,
4
- portIndex,
5
- portModelRunner,
6
- portStore
7
- } from "./chunk-TH5XGPD5.js";
2
+ embed
3
+ } from "./chunk-NI4CIK6W.js";
8
4
  import {
9
5
  standardKeysFrom
10
6
  } from "./chunk-4NXH5ZI6.js";
@@ -14,6 +10,12 @@ import {
14
10
  import {
15
11
  P
16
12
  } from "./chunk-3FYJM7LH.js";
13
+ import {
14
+ hasLane,
15
+ portIndex,
16
+ portModelRunner,
17
+ portStore
18
+ } from "./chunk-LSZTJI7V.js";
17
19
 
18
20
  // workers/worker_public/src/refs.ts
19
21
  var REF = /\[\[(u:[A-Za-z0-9_-]+)\]\]/g;
@@ -1157,21 +1159,279 @@ var glossaryLookup = {
1157
1159
  }
1158
1160
  };
1159
1161
 
1162
+ // workers/worker_public/src/dbtools.ts
1163
+ var DB_CATALOG = [
1164
+ {
1165
+ name: "certificates",
1166
+ description: "The certificate register (a snapshot, not live certification status): one row per issued certificate across the recommendation families.",
1167
+ columns: [
1168
+ { name: "num", type: "text", description: "the printed certificate number, e.g. R60/2021-A-NL1-26.12 (family/prefix per recommendation)" },
1169
+ { name: "family", type: "text", description: "the recommendation family number, e.g. '60' for R 60" },
1170
+ { name: "holder", type: "text", description: "the certificate holder (manufacturer)" },
1171
+ { name: "model", type: "text", description: "the instrument model designation" },
1172
+ { name: "year", type: "number", description: "the issue year", numeric_cast: true },
1173
+ { name: "status", type: "text", description: "Valid | Suspended | Withdrawn" },
1174
+ { name: "pdf_key", type: "text", description: "the /cert-pdf path suffix when the PDF is on file, else empty" }
1175
+ ],
1176
+ default_select: ["num", "family", "holder", "model", "year", "status", "pdf_key"]
1177
+ },
1178
+ {
1179
+ name: "documents",
1180
+ description: "The document identity registry: every publication edition with its family, part, and derived edition status (an edition with a successor is superseded regardless of any copied status field).",
1181
+ columns: [
1182
+ { name: "canonical_id", type: "text", description: "doc:<family>-<edition> slug" },
1183
+ { name: "docidentifier", type: "text", description: "the full identifier with edition" },
1184
+ { name: "family", type: "text", description: "the family key, e.g. R-60" },
1185
+ { name: "part", type: "text", description: "1 | 2 | 3 | A | annexes | sup | empty" },
1186
+ { name: "edition", type: "number", description: "the edition year", numeric_cast: true },
1187
+ { name: "status", type: "text", description: "in-force | superseded | withdrawn (as recorded)" },
1188
+ { name: "derived_status", type: "text", description: "the successor-edge derivation result" },
1189
+ { name: "active", type: "number", description: "1 = the active edition of its family+part" },
1190
+ { name: "superseded_by", type: "text", description: "the successor's canonical_id, else empty" },
1191
+ { name: "title", type: "text", description: "the publication title" }
1192
+ ],
1193
+ default_select: ["canonical_id", "docidentifier", "family", "part", "edition", "derived_status", "active", "superseded_by", "title"]
1194
+ },
1195
+ {
1196
+ name: "graph_nodes",
1197
+ description: "The public citation-graph nodes: documents, families, and vocabulary concepts.",
1198
+ columns: [
1199
+ { name: "id", type: "text", description: "doc:<identifier-slug> | family:<number> | concept:<id>" },
1200
+ { name: "kind", type: "text", description: "doc | family | concept" },
1201
+ { name: "label", type: "text", description: "the display label" }
1202
+ ],
1203
+ default_select: ["id", "kind", "label"]
1204
+ },
1205
+ {
1206
+ name: "graph_edges",
1207
+ description: "The public citation-graph edges between nodes.",
1208
+ columns: [
1209
+ { name: "src", type: "text", description: "the source node id" },
1210
+ { name: "dst", type: "text", description: "the destination node id" },
1211
+ { name: "kind", type: "text", description: "part_of | variant_of | successor | amends | defines" }
1212
+ ],
1213
+ default_select: ["src", "kind", "dst"]
1214
+ },
1215
+ {
1216
+ name: "model_nodes",
1217
+ description: "The Recommendation model plane (per-standard requirement/conformance graphs): the machine-readable nodes behind the verdict engine.",
1218
+ columns: [
1219
+ { name: "standard", type: "text", description: "the standard key, e.g. r60" },
1220
+ { name: "node_id", type: "text", description: "/req/metrological/mpe" },
1221
+ { name: "kind", type: "text", description: "requirement | conformance_test | term | constraint | characteristic | state_machine | dimension" },
1222
+ { name: "name", type: "text", description: "the node's display name" },
1223
+ { name: "clause_doc", type: "text", description: "the provenance document urn" },
1224
+ { name: "clause_ref", type: "text", description: "the clause inside it, e.g. 5.3.2" },
1225
+ { name: "content", type: "text", description: "the node's JSON projection (the checks, thresholds, parameters)", wide: true },
1226
+ { name: "content_hash", type: "text", description: "sha256 of content" }
1227
+ ],
1228
+ default_select: ["standard", "node_id", "kind", "name", "clause_doc", "clause_ref"]
1229
+ },
1230
+ {
1231
+ name: "unit_payloads",
1232
+ description: "Typed retrievable units (tables, formulas, figures, terms) with their producer payloads.",
1233
+ columns: [
1234
+ { name: "unit_id", type: "text", description: "u:table-1" },
1235
+ { name: "doc_id", type: "text", description: "the owning document id" },
1236
+ { name: "docidentifier", type: "text", description: "the publication identifier with part" },
1237
+ { name: "edition", type: "text", description: "the edition year" },
1238
+ { name: "clause_anchor", type: "text", description: "the clause the unit lives in" },
1239
+ { name: "type", type: "text", description: "table | formula | figure | term | requirement" },
1240
+ { name: "payload", type: "text", description: "the producer payload JSON (the table's rows, the formula's math)", wide: true }
1241
+ ],
1242
+ default_select: ["unit_id", "doc_id", "docidentifier", "edition", "clause_anchor", "type"]
1243
+ },
1244
+ {
1245
+ name: "chunks",
1246
+ description: "The indexed corpus chunks (one row per clause-level passage) \u2014 use for exact metadata questions; semantic search is NOT this tool's job.",
1247
+ columns: [
1248
+ { name: "id", type: "text", description: "the chunk id" },
1249
+ { name: "doc_id", type: "text", description: "the source document slug" },
1250
+ { name: "docidentifier", type: "text", description: "the publication identifier with part" },
1251
+ { name: "doctype", type: "text", description: "R | D | B | G | E" },
1252
+ { name: "doc_number", type: "text", description: "60" },
1253
+ { name: "edition", type: "text", description: "the edition year" },
1254
+ { name: "language", type: "text", description: "en | fr | \u2026" },
1255
+ { name: "clause_anchor", type: "text", description: "the clause anchor" },
1256
+ { name: "clause_title", type: "text", description: "the clause title" },
1257
+ { name: "status", type: "text", description: "in-force | superseded" },
1258
+ { name: "superseded_by", type: "text", description: "the superseding docidentifier, else empty" },
1259
+ { name: "corpus", type: "text", description: "clean | dirty" },
1260
+ { name: "tier", type: "text", description: "the quality tier" },
1261
+ { name: "text", type: "text", description: "the passage body (wide \u2014 select only when needed)", wide: true },
1262
+ { name: "fts_text", type: "text", description: "context preamble + body (wide)", wide: true }
1263
+ ],
1264
+ default_select: ["id", "doc_id", "docidentifier", "doctype", "doc_number", "edition", "language", "clause_anchor", "clause_title", "status", "corpus"]
1265
+ }
1266
+ ];
1267
+ function publishedTable(name) {
1268
+ return DB_CATALOG.find((t) => t.name === name);
1269
+ }
1270
+ var FIND_OPS = ["eq", "ne", "lt", "le", "gt", "ge", "in", "like", "between"];
1271
+ var MAX_LIMIT = 25;
1272
+ var DEFAULT_LIMIT = 10;
1273
+ var NUMERIC_OPS = ["lt", "le", "gt", "ge", "between"];
1274
+ function compileFind(args) {
1275
+ const table = publishedTable(String(args?.table ?? ""));
1276
+ if (!table) {
1277
+ return {
1278
+ ok: false,
1279
+ error: `unknown table "${String(args?.table ?? "")}". Published tables: ${DB_CATALOG.map((t) => t.name).join(", ")}.`
1280
+ };
1281
+ }
1282
+ const colNames = table.columns.map((c) => c.name);
1283
+ const colByName = new Map(table.columns.map((c) => [c.name, c]));
1284
+ const params = [];
1285
+ const phrases = [];
1286
+ const p = (n) => `?${n}`;
1287
+ const colRef = (col) => {
1288
+ const c = colByName.get(col);
1289
+ return c.numeric_cast ? `CAST(${col} AS INTEGER)` : col;
1290
+ };
1291
+ for (const w of Array.isArray(args?.where) ? args.where : []) {
1292
+ const col = String(w?.col ?? "");
1293
+ const colDef = colByName.get(col);
1294
+ if (!colDef) {
1295
+ return {
1296
+ ok: false,
1297
+ error: `table "${table.name}" has no column "${col}". Valid columns: ${colNames.join(", ")}.`
1298
+ };
1299
+ }
1300
+ const op = String(w?.op ?? "");
1301
+ if (!FIND_OPS.includes(op)) {
1302
+ return { ok: false, error: `unknown op "${op}". Valid ops: ${FIND_OPS.join(", ")}.` };
1303
+ }
1304
+ const v = w?.value;
1305
+ if (NUMERIC_OPS.includes(op) && !colDef.numeric_cast && colDef.type !== "number") {
1306
+ return { ok: false, error: `op "${op}" needs a numeric column; "${col}" is ${colDef.type}.` };
1307
+ }
1308
+ const ref = colRef(col);
1309
+ if (op === "in") {
1310
+ const list = Array.isArray(v) ? v.map((x) => String(x)) : [String(v)];
1311
+ if (!list.length) return { ok: false, error: `op "in" needs a non-empty value list.` };
1312
+ const holders = list.map((x) => p(params.push(x))).join(", ");
1313
+ phrases.push(`${ref} IN (${holders})`);
1314
+ } else if (op === "between") {
1315
+ const pair = Array.isArray(v) ? v : [void 0, void 0];
1316
+ if (pair.length !== 2) return { ok: false, error: `op "between" needs a two-element value [lo, hi].` };
1317
+ phrases.push(`${ref} BETWEEN ${p(params.push(pair[0]))} AND ${p(params.push(pair[1]))}`);
1318
+ } else if (op === "like") {
1319
+ phrases.push(`${ref} LIKE ${p(params.push(String(v)))}`);
1320
+ } else {
1321
+ const sqlOp = { eq: "=", ne: "!=", lt: "<", le: "<=", gt: ">", ge: ">=" }[op];
1322
+ phrases.push(`${ref} ${sqlOp} ${p(params.push(v))}`);
1323
+ }
1324
+ }
1325
+ const select = (Array.isArray(args?.select) && args.select.length ? args.select : table.default_select).map(String);
1326
+ for (const s of select) {
1327
+ if (!colNames.includes(s)) {
1328
+ return { ok: false, error: `table "${table.name}" has no column "${s}". Valid columns: ${colNames.join(", ")}.` };
1329
+ }
1330
+ }
1331
+ let head;
1332
+ if (args?.agg?.fn) {
1333
+ const fn = String(args.agg.fn);
1334
+ if (!["count", "sum", "avg", "min", "max"].includes(fn)) {
1335
+ return { ok: false, error: `unknown agg fn "${fn}". Valid: count, sum, avg, min, max.` };
1336
+ }
1337
+ let aggExpr = "COUNT(*)";
1338
+ if (fn !== "count") {
1339
+ const acol = String(args.agg.col ?? "");
1340
+ const adef = colByName.get(acol);
1341
+ if (!adef) return { ok: false, error: `agg column "${acol}" is not a column of "${table.name}". Valid columns: ${colNames.join(", ")}.` };
1342
+ aggExpr = `${fn.toUpperCase()}(${colRef(acol)})`;
1343
+ }
1344
+ head = `SELECT ${args?.group_by?.length ? `${args.group_by.map(String).join(", ")}, ` : ""}${aggExpr} AS agg FROM ${table.name}`;
1345
+ for (const g of args?.group_by ?? []) {
1346
+ if (!colNames.includes(String(g))) {
1347
+ return { ok: false, error: `table "${table.name}" has no column "${String(g)}". Valid columns: ${colNames.join(", ")}.` };
1348
+ }
1349
+ }
1350
+ } else {
1351
+ head = `SELECT ${select.join(", ")} FROM ${table.name}`;
1352
+ }
1353
+ const where = phrases.length ? ` WHERE ${phrases.join(" AND ")}` : "";
1354
+ let tail = "";
1355
+ if (args?.group_by?.length) tail += ` GROUP BY ${args.group_by.map(String).join(", ")}`;
1356
+ if (args?.order_by?.col) {
1357
+ const ocol = String(args.order_by.col);
1358
+ if (!colNames.includes(ocol)) {
1359
+ return { ok: false, error: `table "${table.name}" has no column "${ocol}". Valid columns: ${colNames.join(", ")}.` };
1360
+ }
1361
+ const dir = String(args.order_by.dir ?? "desc").toLowerCase() === "asc" ? "ASC" : "DESC";
1362
+ tail += ` ORDER BY ${colRef(ocol)} ${dir}`;
1363
+ }
1364
+ const limit = Math.max(1, Math.min(MAX_LIMIT, Number(args?.limit ?? DEFAULT_LIMIT) || DEFAULT_LIMIT));
1365
+ tail += ` LIMIT ${limit}`;
1366
+ const echo = [
1367
+ `db.find ${table.name}`,
1368
+ args?.where?.length ? `where ${args.where.map((w) => `${w.col} ${w.op} ${JSON.stringify(w.value ?? null)}`).join(" AND ")}` : "all rows",
1369
+ args?.agg?.fn ? `${args.agg.fn}${args.agg.col ? ` ${args.agg.col}` : ""}` : ""
1370
+ ].filter(Boolean).join(" \xB7 ");
1371
+ return {
1372
+ ok: true,
1373
+ sql: `${head}${where}${tail}`,
1374
+ params,
1375
+ echo
1376
+ };
1377
+ }
1378
+ async function runFind(env, args) {
1379
+ const compiled = compileFind(args);
1380
+ if (!compiled.ok) {
1381
+ return {
1382
+ name: "db.find",
1383
+ query: String(args?.table ?? ""),
1384
+ output: `The query was rejected: ${compiled.error} Correct the predicates and call again.`
1385
+ };
1386
+ }
1387
+ try {
1388
+ const { portStore: portStore2 } = await import("./env-LMHGNJTN.js");
1389
+ const res = await portStore2(env).prepare(compiled.sql).bind(...compiled.params).all();
1390
+ const rows = res?.results ?? [];
1391
+ const body = rows.length ? rows.map((r) => JSON.stringify(r)).join("\n") : "No rows matched. Either the predicates are too narrow or the data is absent \u2014 state which, and consider widening.";
1392
+ const aggNote = args?.agg?.fn ? " (aggregate)" : "";
1393
+ return { name: "db.find", query: compiled.echo, output: `${compiled.echo}${aggNote} \u2192 ${rows.length} row(s):
1394
+ ${body}` };
1395
+ } catch (e) {
1396
+ return { name: "db.find", query: compiled.echo, output: `The query failed to run: ${String(e?.message ?? e).slice(0, 200)}` };
1397
+ }
1398
+ }
1399
+ function runSchema(table) {
1400
+ const tables = table ? [publishedTable(String(table))].filter(Boolean) : DB_CATALOG;
1401
+ if (!tables.length) {
1402
+ return {
1403
+ name: "db.schema",
1404
+ query: String(table),
1405
+ output: `Unknown table "${table}". Published tables: ${DB_CATALOG.map((t) => t.name).join(", ")}.`
1406
+ };
1407
+ }
1408
+ const output = tables.map((t) => {
1409
+ const cols = t.columns.map((c) => ` ${c.name} (${c.type}${c.numeric_cast ? ", numeric-cast" : ""}${c.wide ? ", wide" : ""}) \u2014 ${c.description}`).join("\n");
1410
+ return `${t.name} \u2014 ${t.description}
1411
+ ${cols}
1412
+ default select: ${t.default_select.join(", ")}`;
1413
+ }).join("\n\n");
1414
+ return {
1415
+ name: "db.schema",
1416
+ query: table ? String(table) : "catalog",
1417
+ output: `Published tables (compose TOOL db.find with where: [{col, op, value}]; ops: ${FIND_OPS.join(" ")}; values bind safely; like accepts % and _ wildcards):
1418
+
1419
+ ${output}`
1420
+ };
1421
+ }
1422
+
1160
1423
  // workers/worker_public/src/tools.ts
1161
1424
  function parseToolCall(text) {
1162
- const m = /^TOOL\s+([a-z_.]+)\s*(\{[^\n}]*\})?/m.exec(String(text ?? ""));
1425
+ const m = /^TOOL\s+([a-z_.]+)[ \t]*(\{.*)?$/m.exec(String(text ?? ""));
1163
1426
  if (!m) return null;
1164
- let args = {};
1165
- if (m[2]) {
1166
- try {
1167
- args = JSON.parse(m[2]);
1168
- } catch {
1169
- return null;
1170
- }
1171
- } else if (/^TOOL\s+[a-z_.]+\s*\{/m.test(String(text ?? ""))) {
1427
+ const rest = (m[2] ?? "").trim();
1428
+ if (!rest) return { name: m[1].toLowerCase(), args: {} };
1429
+ if (!rest.startsWith("{")) return null;
1430
+ try {
1431
+ return { name: m[1].toLowerCase(), args: JSON.parse(rest) };
1432
+ } catch {
1172
1433
  return null;
1173
1434
  }
1174
- return { name: m[1].toLowerCase(), args };
1175
1435
  }
1176
1436
  var certificatesSearch = {
1177
1437
  name: "certificates.search",
@@ -1187,14 +1447,50 @@ var certificatesSearch = {
1187
1447
  return { name: "certificates.search", query, output };
1188
1448
  }
1189
1449
  };
1190
- var TOOLS_REGISTRY = [certificatesSearch, unitsGet, graphCites, docsSection, glossaryLookup, documentsFamily, licensedSection, verdictEvaluate, conditionsCheck, bibEntry, unitsLookup, unitsConvert];
1450
+ var dbSchema = {
1451
+ name: "db.schema",
1452
+ description: "The published data map: every queryable table (the certificate register, the document registry, the citation graph, the model plane, typed units, the corpus chunks) with its columns, types, and meanings. Call this first whenever a question turns on structured data; then compose db.find.",
1453
+ params: [{ key: "table", required: false, description: "one table's detail; omit for the whole catalog" }],
1454
+ audiences: ["agent", "mcp"],
1455
+ handler: async (_env, args) => {
1456
+ const t = args?.table ? String(args.table) : void 0;
1457
+ return runSchema(t);
1458
+ }
1459
+ };
1460
+ var dbFind = {
1461
+ name: "db.find",
1462
+ description: "Query a published table with typed predicates you compose: where: [{col, op, value}] with ops eq|ne|lt|le|gt|ge|in|like|between, optional select, order_by {col, dir}, limit (\u226425), group_by + agg {fn: count|sum|avg|min|max, col}. Values bind safely; identifiers validate against the schema (errors name the valid columns). Returns the matching rows or aggregate with the query echoed.",
1463
+ params: [
1464
+ { key: "table", required: true, description: "a published table (db.schema lists them)" },
1465
+ { key: "where", required: false, description: "[{col, op, value}] predicates, ANDed" },
1466
+ { key: "select", required: false, description: "columns to return; default per table" },
1467
+ { key: "order_by", required: false, description: "{col, dir: asc|desc}" },
1468
+ { key: "limit", required: false, description: "row cap, \u226425" },
1469
+ { key: "agg", required: false, description: "{fn, col?} aggregate instead of rows; with group_by: [cols]" }
1470
+ ],
1471
+ audiences: ["agent", "mcp"],
1472
+ handler: async (env, args) => {
1473
+ const findArgs = {
1474
+ table: String(args?.table ?? ""),
1475
+ where: Array.isArray(args?.where) ? args.where : [],
1476
+ select: Array.isArray(args?.select) ? args.select : void 0,
1477
+ order_by: args?.order_by && typeof args.order_by === "object" ? args.order_by : void 0,
1478
+ limit: args?.limit != null ? Number(args.limit) : void 0,
1479
+ group_by: Array.isArray(args?.group_by) ? args.group_by : void 0,
1480
+ agg: args?.agg && typeof args.agg === "object" ? args.agg : void 0
1481
+ };
1482
+ if (!findArgs.table) return null;
1483
+ return runFind(env, findArgs);
1484
+ }
1485
+ };
1486
+ var TOOLS_REGISTRY = [dbSchema, dbFind, certificatesSearch, unitsGet, graphCites, docsSection, glossaryLookup, documentsFamily, licensedSection, verdictEvaluate, conditionsCheck, bibEntry, unitsLookup, unitsConvert];
1191
1487
  var TOOL_DECLARATION = [
1192
- "You may use one tool before answering, by writing a single line:",
1488
+ "You may query data before answering, by writing ONE line per call:",
1193
1489
  ...TOOLS_REGISTRY.filter((t) => t.audiences.includes("agent")).map((t) => {
1194
- const shape = `{${t.params.map((p) => `"${p.key}": "<${p.description}>"`).join(", ")}}`;
1490
+ const shape = `{${t.params.map((p) => `"${p.key}": <${p.description}>`).join(", ")}}`;
1195
1491
  return `TOOL ${t.name} ${shape}`;
1196
1492
  }),
1197
- "The worker runs it and returns the result attributed \u2014 phrase the tool's result as what it returned, with the searched string visible in your answer. Use a tool when the question turns on what it answers (including from a photograph). If you do not need it, answer directly without the line."
1493
+ "The worker runs each call and returns the result attributed; you may issue up to three calls across the turns, one per turn, each on its own single line (compact JSON, no line breaks). Structured questions \u2014 counts, latest, filters, per-holder or per-year breakdowns over the register, document editions, model-plane requirements \u2014 start from TOOL db.schema (it lists the queryable tables and their columns), then compose TOOL db.find predicates. Each result arrives attributed: phrase it as what the tool returned, with your query visible in the answer. When you have enough, answer WITHOUT a TOOL line; if no tool helps, answer directly."
1198
1494
  ].join("\n");
1199
1495
  async function runTool(env, call, audience = "agent") {
1200
1496
  const spec = TOOLS_REGISTRY.find((t) => t.name === call.name && t.audiences.includes(audience));
@@ -1,11 +1,7 @@
1
1
  import {
2
2
  embed,
3
- hasLane,
4
- portIndex,
5
- portModelRunner,
6
- portStore,
7
3
  rerank
8
- } from "./chunk-TH5XGPD5.js";
4
+ } from "./chunk-NI4CIK6W.js";
9
5
  import {
10
6
  bubbleConfirmPage,
11
7
  isAllowedBubbleOrigin
@@ -23,6 +19,12 @@ import {
23
19
  import {
24
20
  P
25
21
  } from "./chunk-3FYJM7LH.js";
22
+ import {
23
+ hasLane,
24
+ portIndex,
25
+ portModelRunner,
26
+ portStore
27
+ } from "./chunk-LSZTJI7V.js";
26
28
 
27
29
  // node_modules/@pubid/pubid/dist/grammar/engine.js
28
30
  var ParseFailed = class extends Error {
@@ -0,0 +1,67 @@
1
+ export interface CatalogColumn {
2
+ name: string;
3
+ type: "text" | "number";
4
+ description: string;
5
+ /** ordering/comparison compiles CAST(col AS INTEGER) — textual columns
6
+ * carrying numeric content (certificates.year is TEXT in D1) */
7
+ numeric_cast?: boolean;
8
+ /** excluded from the default select (heavy bodies); still selectable by name */
9
+ wide?: boolean;
10
+ }
11
+ export interface CatalogTable {
12
+ name: string;
13
+ description: string;
14
+ columns: CatalogColumn[];
15
+ default_select: string[];
16
+ }
17
+ export declare const DB_CATALOG: CatalogTable[];
18
+ export declare function publishedTable(name: string): CatalogTable | undefined;
19
+ export declare const FIND_OPS: readonly ["eq", "ne", "lt", "le", "gt", "ge", "in", "like", "between"];
20
+ export type FindOp = (typeof FIND_OPS)[number];
21
+ export interface FindPredicate {
22
+ col: string;
23
+ op: FindOp;
24
+ value: unknown;
25
+ }
26
+ export interface FindArgs {
27
+ table: string;
28
+ where?: FindPredicate[];
29
+ select?: string[];
30
+ order_by?: {
31
+ col: string;
32
+ dir?: "asc" | "desc";
33
+ };
34
+ limit?: number;
35
+ group_by?: string[];
36
+ agg?: {
37
+ fn: "count" | "sum" | "avg" | "min" | "max";
38
+ col?: string;
39
+ };
40
+ }
41
+ export type Compiled = {
42
+ ok: true;
43
+ sql: string;
44
+ params: unknown[];
45
+ echo: string;
46
+ } | {
47
+ ok: false;
48
+ error: string;
49
+ };
50
+ /** Compile validated identifiers + bound parameters. Returns a
51
+ * schema-linked error (naming the valid columns) on any mismatch —
52
+ * the model corrects from the error, the loop continues. */
53
+ export declare function compileFind(args: FindArgs): Compiled;
54
+ /** The db.find handler: compile, run on D1, format deterministically.
55
+ * Every output carries the predicate echo — the answer attributes the
56
+ * rows to the query that produced them. */
57
+ export declare function runFind(env: any, args: FindArgs): Promise<{
58
+ name: string;
59
+ query: string;
60
+ output: string;
61
+ } | null>;
62
+ /** The db.schema handler: the published map, one table or the catalog. */
63
+ export declare function runSchema(table?: string): {
64
+ name: string;
65
+ query: string;
66
+ output: string;
67
+ };
@@ -0,0 +1,18 @@
1
+ import {
2
+ hasLane,
3
+ portBlobs,
4
+ portIndex,
5
+ portKv,
6
+ portModelRunner,
7
+ portRuntime,
8
+ portStore
9
+ } from "./chunk-LSZTJI7V.js";
10
+ export {
11
+ hasLane,
12
+ portBlobs,
13
+ portIndex,
14
+ portKv,
15
+ portModelRunner,
16
+ portRuntime,
17
+ portStore
18
+ };
@@ -1,4 +1,10 @@
1
1
  export declare const PROTOCOL_VERSION = "2025-06-18";
2
+ /** Registry tool name → the MCP-presented name. */
3
+ export declare function mcpName(registryName: string): string;
4
+ /** MCP-presented name → the name the handlers dispatch on. Raw
5
+ * registry names pass through (transition tolerance for early
6
+ * consumers of the unprefixed surface). */
7
+ export declare function registryName(presented: string): string;
2
8
  export interface McpTool {
3
9
  name: string;
4
10
  description: string;
@@ -1,13 +1,14 @@
1
1
  import {
2
2
  handleSearch
3
- } from "./chunk-MWOY24B6.js";
4
- import "./chunk-7AXXR7GD.js";
5
- import "./chunk-TH5XGPD5.js";
3
+ } from "./chunk-5WITTJQD.js";
4
+ import "./chunk-XH5QGX2O.js";
5
+ import "./chunk-NI4CIK6W.js";
6
6
  import "./chunk-W7J5SFXJ.js";
7
7
  import "./chunk-XBZIJMS7.js";
8
8
  import "./chunk-4NXH5ZI6.js";
9
9
  import "./chunk-VT7DR6NQ.js";
10
10
  import "./chunk-3FYJM7LH.js";
11
+ import "./chunk-LSZTJI7V.js";
11
12
  export {
12
13
  handleSearch
13
14
  };
@@ -4,11 +4,12 @@ import {
4
4
  parseToolCall,
5
5
  runTool,
6
6
  toolNote
7
- } from "./chunk-J6LBR6GI.js";
8
- import "./chunk-TH5XGPD5.js";
7
+ } from "./chunk-RKNN3WAV.js";
8
+ import "./chunk-NI4CIK6W.js";
9
9
  import "./chunk-4NXH5ZI6.js";
10
10
  import "./chunk-VT7DR6NQ.js";
11
11
  import "./chunk-3FYJM7LH.js";
12
+ import "./chunk-LSZTJI7V.js";
12
13
  export {
13
14
  TOOLS_REGISTRY,
14
15
  TOOL_DECLARATION,
package/dist/tools.d.ts CHANGED
@@ -7,9 +7,10 @@ export interface ToolResult {
7
7
  query: string;
8
8
  output: string;
9
9
  }
10
- /** The strict protocol: a line `TOOL certificates.search {"query": "…"}`.
11
- * Plain regex parse — no JSON mode needed, tolerant of surrounding
12
- * prose (the model may talk around the call). */
10
+ /** The strict protocol: a line `TOOL <name> {…json…}`. Line-anchored,
11
+ * case-sensitive (prose never trips it); the args are the WHOLE rest
12
+ * of the line parsed as JSON — nested objects (db.find predicates)
13
+ * are legal, and a malformed or unterminated object is not a call. */
13
14
  export declare function parseToolCall(text: string): ToolCall | null;
14
15
  export interface ToolSpec {
15
16
  /** canonical on every surface */