@konneal/engine 0.2.90 → 0.2.92

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.
@@ -0,0 +1,962 @@
1
+ import {
2
+ embed,
3
+ hasLane,
4
+ portIndex,
5
+ portModelRunner
6
+ } from "./chunk-LOBYXEVD.js";
7
+ import {
8
+ standardKeysFrom
9
+ } from "./chunk-LVZTWUVJ.js";
10
+ import {
11
+ THRESHOLDS
12
+ } from "./chunk-2PCUAJJO.js";
13
+ import {
14
+ P
15
+ } from "./chunk-3FYJM7LH.js";
16
+
17
+ // workers/worker_public/src/refs.ts
18
+ var REF = /\[\[(u:[A-Za-z0-9_-]+)\]\]/g;
19
+ function availableUnitIds(hits) {
20
+ const ids = /* @__PURE__ */ new Set();
21
+ for (const h of hits) {
22
+ const u = h.metadata?.unit_id;
23
+ if (u) ids.add(u);
24
+ }
25
+ return ids;
26
+ }
27
+ function parseRefs(text) {
28
+ return [...text.matchAll(REF)].map((m) => m[1]);
29
+ }
30
+ function sanitizeRefs(text, available) {
31
+ const dropped = [];
32
+ const out = text.replace(REF, (full, id) => {
33
+ if (available.has(id)) return full;
34
+ dropped.push(id);
35
+ return "";
36
+ });
37
+ return { text: out, dropped };
38
+ }
39
+ async function resolveBlocks(db, refs) {
40
+ if (!refs.length) return [];
41
+ const uniq = [...new Set(refs)].slice(0, 12);
42
+ const blocks = [];
43
+ for (let i = 0; i < uniq.length; i += 20) {
44
+ const batch = uniq.slice(i, i + 20);
45
+ const placeholders = batch.map((_, n) => `?${n + 1}`).join(",");
46
+ try {
47
+ const res = await db.prepare(`SELECT unit_id, type, docidentifier, edition, payload FROM unit_payloads WHERE unit_id IN (${placeholders})`).bind(...batch).all();
48
+ for (const r of res.results) {
49
+ let payload = {};
50
+ try {
51
+ payload = JSON.parse(String(r.payload));
52
+ } catch {
53
+ continue;
54
+ }
55
+ blocks.push({
56
+ unit_id: String(r.unit_id),
57
+ type: String(r.type),
58
+ docidentifier: String(r.docidentifier ?? ""),
59
+ edition: r.edition ? String(r.edition) : void 0,
60
+ payload
61
+ });
62
+ }
63
+ } catch (e) {
64
+ console.log("resolveBlocks failed:", String(e).slice(0, 150));
65
+ }
66
+ }
67
+ return blocks;
68
+ }
69
+ async function contractV2(db, answer, usedHits) {
70
+ const available = availableUnitIds(usedHits);
71
+ const { text, dropped } = sanitizeRefs(answer, available);
72
+ if (dropped.length) console.log("refs: dropped", dropped.length, "invalid (not in passages)");
73
+ const refs = parseRefs(text);
74
+ const blocks = await resolveBlocks(db, refs);
75
+ return { text, blocks, dropped };
76
+ }
77
+ function tableRetyped(text, availableTable) {
78
+ if (!availableTable) return false;
79
+ return /(^|\n)\s*\|[^\n]+\|\s*(\n\s*\|[-: |]+\|\s*)?(\n|$)/.test(text) && (text.match(/\|/g) ?? []).length >= 6;
80
+ }
81
+
82
+ // workers/worker_public/src/modelplane.ts
83
+ var NODE_RE = /(?:^|[\s("'`])\/(req|conf|term|constraint|characteristic|state-machine|dimension)\/([a-z0-9][a-z0-9_-]*(?:\/[a-z0-9][a-z0-9_-]*)?)(?=[\s)"'`,;:.]|$)/i;
84
+ function modelNodeRefIn(text) {
85
+ if (!text) return null;
86
+ const m = text.match(NODE_RE);
87
+ if (!m) return null;
88
+ const id = `/${m[1].toLowerCase()}/${m[2]}`;
89
+ return id.length <= 120 ? id : null;
90
+ }
91
+ function standardForDocNumber(docNumber) {
92
+ if (!docNumber) return null;
93
+ const models = P().sources?.models;
94
+ if (!models?.standards?.length || !models?.standard_prefix) return null;
95
+ return models.standards.includes(docNumber) ? `${models.standard_prefix}${docNumber}` : null;
96
+ }
97
+ function licensedEntryForPackage(packageId) {
98
+ if (!packageId) return null;
99
+ return (P().sources?.licensed ?? []).find((l) => l.package === packageId) ?? null;
100
+ }
101
+ function licensedEntryForDocNumber(docNumber) {
102
+ if (!docNumber) return null;
103
+ return (P().sources?.licensed ?? []).find((l) => String(l.doc_number ?? "") === docNumber) ?? null;
104
+ }
105
+ function licenseBoundaryNote(docNumber, standardKeys) {
106
+ const entry = licensedEntryForDocNumber(docNumber);
107
+ if (!entry || standardKeys && standardKeys.has(entry.key)) return void 0;
108
+ const pointer = P().prompts?.vars?.license_declare_pointer;
109
+ return `License boundary \u2014 the question is about ${licenseBoundaryName(entry)}, a licensed publication (entitlement key ${entry.key}). The caller's organization license does not cover its text, so no passage of it was retrieved and NONE of its procedural content (steps, parameters, severities, limits) may be stated, paraphrased or recalled from memory. You MAY answer at the citation level: name the standard and edition, and cite the invoking clause from the PUBLIC passages in context (the Recommendation's own applicability and normative references are public and stay answerable). Then say the organization's license does not cover the standard's text` + (pointer ? ` and point to the declare flow: ${pointer}.` : ".");
110
+ }
111
+ function licenseBoundaryName(entry) {
112
+ const id = entry.doc_number ? ` ${entry.doc_number}` : ` ${entry.package}`;
113
+ return `${entry.title ?? "standard"}${entry.edition ? ` (${entry.edition})` : ""} \u2014${id}`;
114
+ }
115
+ function licenseBoundaryRefusal(docNumber, standardKeys) {
116
+ const entry = licensedEntryForDocNumber(docNumber);
117
+ if (!entry || standardKeys && standardKeys.has(entry.key)) return void 0;
118
+ const pointer = P().prompts?.vars?.license_declare_pointer;
119
+ return `${licenseBoundaryName(entry)} is a licensed publication and your organization's license does not cover its text, so I can't quote or summarize its procedure. I can answer at the citation level \u2014 the standard's title and edition, and the clause your Recommendation invokes \u2014 and the public ${P().publisher.name} content in full.` + (pointer ? ` To unlock the full text, an org admin can declare the license under ${pointer}.` : "");
120
+ }
121
+ async function fetchNode(env, standard, nodeId) {
122
+ try {
123
+ const row = await env.DB.prepare(
124
+ "SELECT standard, node_id, kind, name, clause_doc, clause_ref, content FROM model_nodes WHERE standard = ?1 AND node_id = ?2"
125
+ ).bind(standard, nodeId).first();
126
+ if (!row) return null;
127
+ const content = JSON.parse(String(row.content));
128
+ const clause = row.clause_doc && row.clause_ref ? { doc: String(row.clause_doc), ref: String(row.clause_ref), urn: `${row.clause_doc}#clause-${row.clause_ref}` } : row.clause_doc ? { doc: String(row.clause_doc), ref: "", urn: String(row.clause_doc) } : null;
129
+ return {
130
+ standard: String(row.standard),
131
+ node_id: String(row.node_id),
132
+ kind: String(row.kind),
133
+ name: String(row.name ?? row.node_id),
134
+ clause,
135
+ content
136
+ };
137
+ } catch {
138
+ return null;
139
+ }
140
+ }
141
+ async function bindModelNode(env, opts) {
142
+ const nodeId = modelNodeRefIn(opts.label) ?? modelNodeRefIn(opts.query);
143
+ if (!nodeId) return null;
144
+ const gate = (node) => {
145
+ if (!node) return null;
146
+ const entry = licensedEntryForPackage(node.standard);
147
+ return entry && !(opts.standardKeys?.has(entry.key) ?? false) ? { ...node, gated: true, content: {} } : node;
148
+ };
149
+ if (opts.standard) return gate(await fetchNode(env, opts.standard, nodeId));
150
+ try {
151
+ const rows = await env.DB.prepare("SELECT standard FROM model_nodes WHERE node_id = ?1 LIMIT 2").bind(nodeId).all();
152
+ const standards = (rows?.results ?? []).map((r) => String(r.standard));
153
+ if (standards.length === 1) return gate(await fetchNode(env, standards[0], nodeId));
154
+ return null;
155
+ } catch {
156
+ return null;
157
+ }
158
+ }
159
+ function clip(s, n = 500) {
160
+ const t = String(s ?? "").trim();
161
+ return t.length <= n ? t : t.slice(0, n - 1).trimEnd() + " \u2026";
162
+ }
163
+ function applicabilityText(app) {
164
+ if (!app || typeof app !== "object") return "";
165
+ const parts = [];
166
+ for (const [dim, cond] of Object.entries(app)) {
167
+ if (Array.isArray(cond)) parts.push(`${dim.replace(/_/g, " ")}: ${cond.join(", ")}`);
168
+ else if (cond && typeof cond === "object" && Array.isArray(cond.values)) {
169
+ parts.push(`${dim.replace(/_/g, " ")} (${cond.match ?? "any"}): ${cond.values.join(", ")}`);
170
+ }
171
+ }
172
+ return parts.join("; ");
173
+ }
174
+ function modelGroundingBlock(node) {
175
+ const c = node.content ?? {};
176
+ const lines = [];
177
+ lines.push(
178
+ P().prompts.vars.model_grounding_intro ?? "Model grounding \u2014 the model plane's own statement:"
179
+ );
180
+ lines.push(`Node: ${node.node_id} (${node.kind.replace(/_/g, " ")}) \u2014 ${node.name} [${node.standard}]`);
181
+ if (node.clause) lines.push(`Provenance: ${node.clause.urn}`);
182
+ if (c.statement) lines.push(`Statement: ${clip(c.statement)}`);
183
+ if (c.definition) lines.push(`Definition: ${clip(c.definition)}`);
184
+ if (c.purpose) lines.push(`Purpose: ${clip(c.purpose)}`);
185
+ const limit = c.limit ?? {};
186
+ if (limit.expression) lines.push(`Machine limit (the constraint the platform's verdict engine evaluates \u2014 quote it verbatim): ${limit.expression}`);
187
+ if (limit.accepts?.verdict) lines.push(`Machine limit: ${limit.accepts.verdict} ${limit.accepts.op} ${limit.accepts.limit} (the canonical acceptance chain)`);
188
+ if (c.check) lines.push(`Machine check: ${c.check}`);
189
+ if (c.derive) lines.push(`Derivation: ${c.derive}${Array.isArray(c.inputs) ? ` (inputs: ${c.inputs.join(", ")})` : ""}`);
190
+ const app = applicabilityText(c.applicability);
191
+ const scopeApp = applicabilityText(c.scope_applicability);
192
+ if (app || scopeApp) lines.push(`Applicability: ${[scopeApp, app].filter(Boolean).join("; ")}`);
193
+ if (Array.isArray(c.binds_to) && c.binds_to.length) lines.push(`Binds to: ${c.binds_to.join(", ")}`);
194
+ if (Array.isArray(c.targets) && c.targets.length) lines.push(`Verifies requirements: ${c.targets.join(", ")}`);
195
+ if (Array.isArray(c.preconditions) && c.preconditions.length) {
196
+ const pcs = c.preconditions.map((p) => `${p.id}: ${clip(p.check ?? (p.state ? `state = ${p.state}` : ""), 120)}`).join("; ");
197
+ lines.push(`Run-validity preconditions (a violation voids the run \u2014 invalid, never a fail): ${pcs}`);
198
+ }
199
+ if (c.acceptance_criteria?.description) lines.push(`Acceptance: ${clip(c.acceptance_criteria.description, 300)}`);
200
+ if (c.violation_meaning) lines.push(`Violation meaning (verbatim): ${clip(c.violation_meaning, 300)} \u2014 on violation: ${c.on_violation ?? "invalid"}`);
201
+ if (Array.isArray(c.values) && c.values.length) {
202
+ lines.push(`Values: ${c.values.map((v) => `${v.id}${v.implies?.length ? ` (implies ${v.implies.join(", ")})` : ""}`).join("; ")}`);
203
+ }
204
+ if (c.source_discrepancy) {
205
+ const sd = c.source_discrepancy;
206
+ lines.push(
207
+ `DECLARED SOURCE DISCREPANCY \u2014 the model and the text disagree; you MUST surface this and cite both: ${clip(sd.summary, 300)} Sources: ${(sd.sources ?? []).join(" and ")}. The model ${sd.resolution === "follows_clause_x" ? "follows one side" : "records the conflict without resolving it"}: ${clip(sd.rationale, 300)}`
208
+ );
209
+ }
210
+ lines.push(
211
+ "Rules for this answer: the machine facts (the constraint, the applicability, the acceptance, the provenance) come from THIS node \u2014 quote the machine limit verbatim, never invent one the node does not carry. If this model content and a prose passage disagree \u2014 including a passage from a different edition \u2014 say so explicitly and cite both (this node and the prose clause)."
212
+ );
213
+ return lines.join("\n");
214
+ }
215
+ function modelCitation(node) {
216
+ return {
217
+ doc_id: `model:${node.standard}`,
218
+ docidentifier: `${P().publisher.name} SMART model (${(() => {
219
+ const prefix = P().sources?.models?.standard_prefix ?? "";
220
+ const letter = prefix.replace(/^.*-/, "").toUpperCase();
221
+ return String(node.standard).replace(new RegExp(`^${prefix}`, "i"), `${letter} `);
222
+ })()})`,
223
+ edition: "",
224
+ language: "en",
225
+ clause_anchor: node.clause?.ref || "model",
226
+ clause_title: `${node.kind.replace(/_/g, " ")} \u2014 ${node.name} (${node.node_id})`,
227
+ status: "in-force",
228
+ corpus: "smart-model",
229
+ quality: "verified",
230
+ url: void 0,
231
+ snippet: `${node.node_id}${node.clause ? ` \xB7 ${node.clause.urn}` : ""}${node.content?.statement ? ` \u2014 ${clip(node.content.statement, 240)}` : ""}`,
232
+ score: 1
233
+ };
234
+ }
235
+ function modelEcho(node) {
236
+ return {
237
+ node_id: node.node_id.slice(0, 120),
238
+ kind: node.kind.slice(0, 40),
239
+ standard: node.standard.slice(0, 40),
240
+ ...node.clause?.urn ? { clause: node.clause.urn.slice(0, 120) } : {}
241
+ };
242
+ }
243
+
244
+ // workers/worker_public/src/verdict.ts
245
+ function tokenize(src) {
246
+ const toks = [];
247
+ let i = 0;
248
+ const s = src.replace(/\s+/g, " ");
249
+ while (i < s.length) {
250
+ const c = s[i];
251
+ if (c === " ") {
252
+ i++;
253
+ continue;
254
+ }
255
+ if (/[0-9.]/.test(c)) {
256
+ const m = s.slice(i).match(/^[0-9]*\.?[0-9]+/);
257
+ toks.push({ t: "num", v: Number(m[0]) });
258
+ i += m[0].length;
259
+ continue;
260
+ }
261
+ if (/[A-Za-z_]/.test(c)) {
262
+ const m = s.slice(i).match(/^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*/);
263
+ toks.push({ t: "id", v: m[0] });
264
+ i += m[0].length;
265
+ continue;
266
+ }
267
+ const two = s.slice(i, i + 2);
268
+ if ([">=", "<=", "==", "!="].includes(two)) {
269
+ toks.push({ t: "op", v: two });
270
+ i += 2;
271
+ continue;
272
+ }
273
+ if ("+-*/()<>".includes(c)) {
274
+ toks.push({ t: "op", v: c });
275
+ i++;
276
+ continue;
277
+ }
278
+ throw new Error(`bad char ${c}`);
279
+ }
280
+ return toks;
281
+ }
282
+ function parseAndEval(src, params) {
283
+ const toks = tokenize(src);
284
+ let p = 0;
285
+ const peek = () => toks[p];
286
+ const eat = (v) => {
287
+ const t = toks[p++];
288
+ if (v && (!t || t.t !== "op" || t.v !== v)) throw new Error(`expected ${v}`);
289
+ return t;
290
+ };
291
+ const isKw = (k) => {
292
+ const t = peek();
293
+ return t && t.t === "id" && t.v.toLowerCase() === k;
294
+ };
295
+ function or() {
296
+ let l = and();
297
+ while (isKw("or")) {
298
+ p++;
299
+ const r = and();
300
+ l = truthy(l) || truthy(r);
301
+ }
302
+ return l;
303
+ }
304
+ function and() {
305
+ let l = not();
306
+ while (isKw("and")) {
307
+ p++;
308
+ const r = not();
309
+ l = truthy(l) && truthy(r);
310
+ }
311
+ return l;
312
+ }
313
+ function not() {
314
+ if (isKw("not")) {
315
+ p++;
316
+ return !truthy(not());
317
+ }
318
+ return cmp();
319
+ }
320
+ function cmp() {
321
+ const l = add();
322
+ const t = peek();
323
+ if (t && t.t === "op" && [">=", "<=", ">", "<", "==", "!="].includes(t.v)) {
324
+ p++;
325
+ const r = add();
326
+ switch (t.v) {
327
+ case ">=":
328
+ return num(l) >= num(r);
329
+ case "<=":
330
+ return num(l) <= num(r);
331
+ case ">":
332
+ return num(l) > num(r);
333
+ case "<":
334
+ return num(l) < num(r);
335
+ case "==":
336
+ return num(l) === num(r);
337
+ default:
338
+ return num(l) !== num(r);
339
+ }
340
+ }
341
+ return l;
342
+ }
343
+ function add() {
344
+ let l = mul();
345
+ for (; ; ) {
346
+ const t = peek();
347
+ if (t && t.t === "op" && (t.v === "+" || t.v === "-")) {
348
+ p++;
349
+ const r = mul();
350
+ l = t.v === "+" ? num(l) + num(r) : num(l) - num(r);
351
+ } else return l;
352
+ }
353
+ }
354
+ function mul() {
355
+ let l = unary();
356
+ for (; ; ) {
357
+ const t = peek();
358
+ if (t && t.t === "op" && (t.v === "*" || t.v === "/")) {
359
+ p++;
360
+ const r = unary();
361
+ l = t.v === "*" ? num(l) * num(r) : num(l) / num(r);
362
+ } else return l;
363
+ }
364
+ }
365
+ function unary() {
366
+ const t = peek();
367
+ if (t && t.t === "op" && t.v === "-") {
368
+ p++;
369
+ return -num(unary());
370
+ }
371
+ return atom();
372
+ }
373
+ function atom() {
374
+ const t = eat();
375
+ if (!t) throw new Error("unexpected end");
376
+ if (t.t === "num") return t.v;
377
+ if (t.t === "id") {
378
+ if (params[t.v] !== void 0) return params[t.v];
379
+ throw new Error(`missing ${t.v}`);
380
+ }
381
+ if (t.v === "(") {
382
+ const v = or();
383
+ eat(")");
384
+ return v;
385
+ }
386
+ throw new Error(`unexpected ${t.v}`);
387
+ }
388
+ const truthy = (v) => typeof v === "boolean" ? v : v !== 0;
389
+ const num = (v) => typeof v === "boolean" ? v ? 1 : 0 : v;
390
+ const out = or();
391
+ if (p !== toks.length) throw new Error("trailing tokens");
392
+ return out;
393
+ }
394
+ function oclBody(s) {
395
+ const m = String(s ?? "").match(/ocl\{([\s\S]*?)\}/);
396
+ return m ? m[1].trim() : null;
397
+ }
398
+ function extractChecks(content) {
399
+ if (!content || typeof content !== "object") return [];
400
+ const c = content;
401
+ const out = [];
402
+ const push = (e) => {
403
+ const b = e && oclBody(e);
404
+ if (b) out.push(b);
405
+ };
406
+ push(c.check);
407
+ push(c.limit?.expression);
408
+ push(c.acceptance_criteria?.limit && !c.acceptance_criteria.limit.expression?.includes("ocl{") ? null : c.acceptance_criteria?.limit?.expression);
409
+ const st = c.acceptance_criteria?.limit;
410
+ if (st?.expression && st.operator && st.threshold_expression) {
411
+ out.push(`${st.expression} ${st.operator} ${st.threshold_expression}`);
412
+ }
413
+ return [...new Set(out)];
414
+ }
415
+ function symbolsIn(checks) {
416
+ const ids = /* @__PURE__ */ new Set();
417
+ const KEYWORDS = /* @__PURE__ */ new Set(["and", "or", "not"]);
418
+ for (const chk of checks) {
419
+ try {
420
+ for (const t of tokenize(chk)) if (t.t === "id" && !KEYWORDS.has(t.v.toLowerCase())) ids.add(t.v);
421
+ } catch {
422
+ }
423
+ }
424
+ return [...ids];
425
+ }
426
+ function parseNumber(raw) {
427
+ let s = raw.replace(/[ ,]/g, "");
428
+ s = s.replace(/\.(\d{3})$/, "$1");
429
+ return Number(s.replace(/,(?=\d{3}\b)/g, ""));
430
+ }
431
+ function extractParams(query, symbols) {
432
+ const params = {};
433
+ for (const sym of symbols) {
434
+ const leaf = sym.split(".").pop() ?? sym;
435
+ const esc = leaf.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
436
+ const re = new RegExp(`\\b${esc}\\b\\D{0,14}?([0-9][0-9 ,.]*[0-9])`, "iu");
437
+ const m = query.match(re);
438
+ if (m) {
439
+ const v = parseNumber(m[1]);
440
+ if (Number.isFinite(v)) params[sym] = v;
441
+ }
442
+ }
443
+ return params;
444
+ }
445
+ function evaluate(content, query) {
446
+ const c = content && typeof content === "object" ? content : {};
447
+ const checks = extractChecks(content);
448
+ if (!checks.length) return null;
449
+ const symbols = symbolsIn(checks);
450
+ const params = extractParams(query, symbols);
451
+ const missing = symbols.filter((s) => params[s] === void 0);
452
+ const machine = checks.map((expression) => {
453
+ const values = {};
454
+ try {
455
+ for (const t of tokenize(expression)) if (t.t === "id" && params[t.v] !== void 0) values[t.v] = params[t.v];
456
+ } catch {
457
+ }
458
+ let result = null;
459
+ if (missing.length === 0) {
460
+ try {
461
+ result = !!parseAndEval(expression, params);
462
+ } catch {
463
+ result = null;
464
+ }
465
+ }
466
+ return { expression, symbolic: expression, values, result };
467
+ });
468
+ if (missing.length) {
469
+ return { verdict: "void", missing, checks: machine };
470
+ }
471
+ const failed = machine.some((m) => m.result === false);
472
+ const evaluable = machine.some((m) => m.result !== null);
473
+ if (!evaluable) return null;
474
+ return {
475
+ verdict: failed ? "fail" : "pass",
476
+ on_violation: failed ? String(c.on_violation ?? "invalid") : void 0,
477
+ violation_meaning: failed ? typeof c.violation_meaning === "string" ? c.violation_meaning : void 0 : void 0,
478
+ missing: [],
479
+ checks: machine
480
+ };
481
+ }
482
+ function verdictNote(v, node) {
483
+ const lines = [
484
+ `Machine verdict (deterministic evaluation of node ${node.node_id}${node.clause?.urn ? `, ${node.clause.urn}` : ""}) \u2014 the service EXECUTED the node's machine check against the values stated in the question:`
485
+ ];
486
+ for (const c of v.checks) {
487
+ const vals = Object.entries(c.values).map(([k, n]) => `${k}=${n}`).join(", ");
488
+ lines.push(`- ${c.expression}${vals ? ` [${vals}]` : ""} \u2192 ${c.result === null ? "not evaluated" : c.result ? "holds" : "VIOLATED"}`);
489
+ }
490
+ if (v.verdict === "void") {
491
+ lines.push(`VERDICT: VOID \u2014 the question does not state: ${v.missing.join(", ")}. Say exactly what is missing; never assume values.`);
492
+ } else if (v.verdict === "pass") {
493
+ lines.push(`VERDICT: PASS \u2014 every machine check holds at the stated values. Present this verdict, the arithmetic above, and cite the node's clause.`);
494
+ } else {
495
+ lines.push(`VERDICT: ${String(v.on_violation ?? "FAIL").toUpperCase()} \u2014 a machine check is violated. Present this verdict, the arithmetic, the violation meaning verbatim, and cite the node's clause.`);
496
+ }
497
+ lines.push("This verdict is computed data \u2014 quote it faithfully; do not recompute, soften, or contradict it.");
498
+ return lines.join("\n");
499
+ }
500
+
501
+ // workers/worker_public/src/conditions.ts
502
+ var NUM = String.raw`-?\d+(?:[.,]\d+)?`;
503
+ function quantitiesIn(query) {
504
+ const out = {};
505
+ const num = (s) => Number(s.replace(",", "."));
506
+ const put = (kind, stated, stated_unit, si) => {
507
+ if (Number.isFinite(si)) out[kind] = { stated, stated_unit, si };
508
+ };
509
+ const tempC = query.match(new RegExp(`(${NUM})\\s*(?:\xB0\\s*)?C\\b`));
510
+ if (tempC) put("temperature", num(tempC[1]), "degC", num(tempC[1]) + 273.15);
511
+ const tempK = query.match(new RegExp(`(${NUM})\\s*K\\b`));
512
+ if (tempK && out.temperature === void 0) put("temperature", num(tempK[1]), "K", num(tempK[1]));
513
+ const rh = query.match(new RegExp(`(${NUM})\\s*%\\s*(?:RH\\b|relative\\s+humidity)?`, "i"));
514
+ if (rh) put("relative_humidity", num(rh[1]), "%", num(rh[1]) / 100);
515
+ const hours = query.match(new RegExp(`(${NUM})\\s*h\\b`, "i"));
516
+ if (hours) put("duration", num(hours[1]), "h", num(hours[1]) * 3600);
517
+ const days = query.match(new RegExp(`(${NUM})\\s*days?\\b`, "i"));
518
+ if (days && out.duration === void 0) put("duration", num(days[1]), "d", num(days[1]) * 86400);
519
+ return out;
520
+ }
521
+ function scoreSet(entries, q) {
522
+ const checks = [];
523
+ let distance = 0;
524
+ let stated = 0;
525
+ for (const e of entries) {
526
+ const siEntry = e;
527
+ const statedQ = q[e.quantity_kind];
528
+ if (!statedQ || !siEntry?.si) continue;
529
+ const tol = Number(String(siEntry.tolerance ?? "0").replace(",", "."));
530
+ const tolSi = (Number.isFinite(tol) ? tol : 0) * (siEntry.si.unit === "K" ? 1 : siEntry.si.unit === "1" ? 0.01 : 1);
531
+ const in_band = statedQ.si >= siEntry.si.value - tolSi && statedQ.si <= siEntry.si.value + tolSi;
532
+ const gap = Math.max(0, statedQ.si - (siEntry.si.value + tolSi), siEntry.si.value - tolSi - statedQ.si);
533
+ distance += gap / Math.max(tolSi, 1);
534
+ stated += 1;
535
+ checks.push({
536
+ quantity_kind: e.quantity_kind,
537
+ band: `${siEntry.si.value} ${siEntry.si.unit} \xB1${tolSi}`,
538
+ stated: statedQ.stated,
539
+ stated_unit: statedQ.stated_unit,
540
+ in_band
541
+ });
542
+ }
543
+ return stated ? { checks, distance, stated } : null;
544
+ }
545
+ function evaluateConditionSets(nodes, query) {
546
+ const q = quantitiesIn(query);
547
+ const kinds = Object.keys(q);
548
+ if (!kinds.length) return null;
549
+ const scored = [];
550
+ for (const n of nodes) {
551
+ const c = n.content && typeof n.content === "object" ? n.content : {};
552
+ const payload = c.payload ?? {};
553
+ const entries = Array.isArray(payload.entries) ? payload.entries : [];
554
+ if (!entries.length) continue;
555
+ const s = scoreSet(entries, q);
556
+ if (s) scored.push({ node_id: n.node_id, checks: s.checks, distance: s.distance });
557
+ }
558
+ if (!scored.length) return null;
559
+ const matched = scored.filter((s) => s.checks.every((c) => c.in_band));
560
+ scored.sort((a, b) => a.distance - b.distance);
561
+ if (matched.length) {
562
+ return {
563
+ verdict: "pass",
564
+ matched: matched.map((m) => m.node_id),
565
+ checks: matched[0].checks,
566
+ note: `VERDICT: PASS \u2014 the stated combination (${kinds.join(", ")}) matches a severity set (${matched[0].checks.map((c) => c.band).join("; ")}). Present this verdict and cite the set's clause. The machine set identifier rides the verdict block as data \u2014 never write it in your prose.`
567
+ };
568
+ }
569
+ const nearest = scored[0];
570
+ return {
571
+ verdict: "fail",
572
+ matched: [],
573
+ nearest: { node_id: nearest.node_id, distance: Number(nearest.distance.toFixed(2)), bands: nearest.checks.map((c) => c.band) },
574
+ checks: nearest.checks,
575
+ note: `VERDICT: FAIL \u2014 no severity set admits the stated combination. The nearest set (bands: ${nearest.checks.map((c) => c.band).join("; ")}) is the closest match. Say the combination is outside the menu and describe the nearest set's bands; never soften it. The machine set identifier rides the verdict block as data \u2014 never write it in your prose.`
576
+ };
577
+ }
578
+
579
+ // workers/worker_public/src/tools-content.ts
580
+ var slug = (docidentifier) => docidentifier.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
581
+ var unitsGet = {
582
+ name: "units.get",
583
+ description: "Fetch typed Recommendation content \u2014 a table, formula or figure as structured data (columns, rows, MathML, caption), by its unit id. The machine-consumable form of a Recommendation's content, for computing with rather than reading.",
584
+ params: [{ key: "unit_id", required: true, description: "the unit id exactly as an answer's [[u:\u2026]] reference spells it" }],
585
+ audiences: ["mcp"],
586
+ handler: async (env, args) => {
587
+ const unit_id = String(args?.unit_id ?? "").trim().replace(/^\[?\[?u:/, "u:").replace(/]?\]?$/, "");
588
+ if (!/^u:[\w.-]+$/.test(unit_id)) return null;
589
+ const blocks = await resolveBlocks(env.DB, [unit_id]);
590
+ if (!blocks.length) {
591
+ return { name: "units.get", query: unit_id, output: `No typed unit "${unit_id}" exists in the indexed payloads. State this plainly.` };
592
+ }
593
+ return {
594
+ name: "units.get",
595
+ query: unit_id,
596
+ output: JSON.stringify(
597
+ blocks.map((b) => ({ unit_id: b.unit_id, type: b.type, docidentifier: b.docidentifier, payload: b.payload }))
598
+ )
599
+ };
600
+ }
601
+ };
602
+ var graphCites = {
603
+ name: "graph.cites",
604
+ description: "The bibliography edges: what a publication's own bibliography actually cites, extracted from its indexed bibliography sections. Returns the cited works' labels for a document (optionally scoped to an edition).",
605
+ params: [
606
+ { key: "doc", required: true, description: "the publication identifier, e.g. R 60-1:2021" },
607
+ { key: "edition", required: false, description: "an edition year to scope, e.g. 2021" }
608
+ ],
609
+ audiences: ["mcp"],
610
+ handler: async (env, args) => {
611
+ const doc = String(args?.doc ?? "").trim();
612
+ if (doc.length < 3) return null;
613
+ const edition = args?.edition ? String(args.edition).trim() : null;
614
+ const pat = `%${doc.replace(/[:\s]+/g, "%")}%${edition ? edition : ""}%`;
615
+ try {
616
+ const rows = await env.DB.prepare(
617
+ "SELECT DISTINCT n.label AS label FROM graph_edges e JOIN documents d ON e.src = d.canonical_id JOIN graph_nodes n ON e.dst = n.id WHERE d.docidentifier LIKE ?1 AND e.kind = 'cites' ORDER BY label LIMIT 60"
618
+ ).bind(pat).all();
619
+ const labels = (rows.results ?? []).map((r) => r.label).filter(Boolean);
620
+ return {
621
+ name: "graph.cites",
622
+ query: `${doc}${edition ? ` (${edition})` : ""}`,
623
+ output: labels.length ? `The publication's bibliography cites:
624
+ ${labels.map((l) => `- ${l}`).join("\n")}` : `No bibliography citations are indexed for "${doc}"${edition ? ` (${edition})` : ""}. State this plainly.`
625
+ };
626
+ } catch {
627
+ return null;
628
+ }
629
+ }
630
+ };
631
+ var docsSection = {
632
+ name: "docs.section",
633
+ description: "Fetch one clause of a publication's rendered document \u2014 its text and its permanent deep-link URL \u2014 for agents that need the human-formatted passage with its anchor.",
634
+ params: [
635
+ { key: "doc", required: true, description: "the publication identifier, e.g. R 60-1:2021" },
636
+ { key: "clause", required: true, description: "the clause anchor, e.g. 5.1.1 or annex-b" }
637
+ ],
638
+ audiences: ["mcp"],
639
+ handler: async (env, args) => {
640
+ const doc = String(args?.doc ?? "").trim();
641
+ const clause = String(args?.clause ?? "").trim();
642
+ if (doc.length < 3 || !clause) return null;
643
+ try {
644
+ const rows = await env.DB.prepare(
645
+ "SELECT docidentifier, clause_anchor, clause_title, text FROM chunks WHERE docidentifier LIKE ?1 AND REPLACE(clause_anchor, ' ', '') = ?2 LIMIT 1"
646
+ ).bind(`%${doc.replace(/[:\s]+/g, "%")}%`, clause).all();
647
+ const r = (rows.results ?? [])[0];
648
+ if (!r) {
649
+ return { name: "docs.section", query: `${doc} \xA7${clause}`, output: `No clause "${clause}" is indexed for "${doc}". State this plainly.` };
650
+ }
651
+ const url = `https://www.ommisa.org/docs/${slug(r.docidentifier)}.html#${r.clause_anchor}`;
652
+ return {
653
+ name: "docs.section",
654
+ query: `${r.docidentifier} \xA7${r.clause_anchor}`,
655
+ output: JSON.stringify({ docidentifier: r.docidentifier, clause: r.clause_anchor, title: r.clause_title, url, text: (r.text ?? "").slice(0, 4e3) })
656
+ };
657
+ } catch {
658
+ return null;
659
+ }
660
+ }
661
+ };
662
+ var documentsFamily = {
663
+ name: "documents.family",
664
+ description: "Look up the publication registry for a family: every edition with its derived status (in-force/superseded), which edition is ACTIVE (terminal of the successor chain), and supersession links. Use for current/latest-edition and edition-history questions.",
665
+ params: [{ key: "family", required: true, description: "the family key, e.g. R-60 (series letter and number)" }],
666
+ audiences: ["mcp"],
667
+ handler: async (env, args) => {
668
+ const family = String(args?.family ?? "").trim().toUpperCase();
669
+ if (!/^[A-Z]-\d{1,3}$/.test(family)) return null;
670
+ try {
671
+ const rows = await env.DB.prepare(
672
+ "SELECT d.docidentifier, d.derived_status, d.active, s.docidentifier AS succ FROM documents d LEFT JOIN documents s ON d.superseded_by = s.canonical_id WHERE d.family = ?1 ORDER BY d.part, d.edition"
673
+ ).bind(family).all();
674
+ const lines = (rows.results ?? []).map(
675
+ (r) => `${r.docidentifier} \u2014 ${r.derived_status}${r.active ? " [ACTIVE]" : ""}${r.succ ? ` \u2192 superseded by ${r.succ}` : ""}`
676
+ );
677
+ if (!lines.length) {
678
+ return { name: "documents.family", query: family, output: `No editions are registered for the family ${family}. State this plainly.` };
679
+ }
680
+ return { name: "documents.family", query: family, output: lines.join("\n") };
681
+ } catch {
682
+ return null;
683
+ }
684
+ }
685
+ };
686
+ var licensedSection = {
687
+ name: "licensed.section",
688
+ description: "Fetch one clause of a licensed standard's typed model content \u2014 requirements, condition sets and parameters as structured data \u2014 behind the caller's license entitlement keys. An unentitled caller receives the license boundary: the standard's title and edition and the declare flow, never its text.",
689
+ params: [
690
+ { key: "doc", required: true, description: "the standard's document number, e.g. 60068-2-30 or 61000-4-2" },
691
+ { key: "clause", required: true, description: "the clause number inside the standard, e.g. 5 or 9" },
692
+ { key: "licensed_standards", required: true, description: `the caller's license entitlement keys, e.g. ["std:iec-60068-2-30"] \u2014 validated against the licenses this deployment declares; keys it does not know drop` }
693
+ ],
694
+ audiences: ["mcp"],
695
+ handler: async (env, args) => {
696
+ const doc = String(args?.doc ?? "").trim();
697
+ const clause = String(args?.clause ?? "").trim();
698
+ if (doc.length < 3 || !clause) return null;
699
+ const docNumber = doc.replace(/^(?:ISO\/IEC|ISO|IEC)\s+/i, "").trim();
700
+ const entry = licensedEntryForDocNumber(docNumber);
701
+ if (!entry) {
702
+ return {
703
+ name: "licensed.section",
704
+ query: `${doc} \xA7${clause}`,
705
+ output: `"${doc}" is not among the licensed standards this deployment keys. For clauses of the public corpus use the docs.section tool instead. State this plainly.`
706
+ };
707
+ }
708
+ const keys = standardKeysFrom({ licensed_standards: args?.licensed_standards });
709
+ if (!keys.has(entry.key)) {
710
+ const refusal = licenseBoundaryRefusal(docNumber, keys);
711
+ return {
712
+ name: "licensed.section",
713
+ query: `${doc} \xA7${clause}`,
714
+ output: refusal ?? "License boundary \u2014 the caller's entitlement set does not cover this standard's text."
715
+ };
716
+ }
717
+ try {
718
+ const rows = await env.DB.prepare(
719
+ "SELECT node_id, kind, name, clause_ref, content FROM model_nodes WHERE standard = ?1 AND clause_ref = ?2 ORDER BY node_id LIMIT 20"
720
+ ).bind(entry.package, clause).all();
721
+ const nodes = rows.results ?? [];
722
+ if (!nodes.length) {
723
+ const c = await env.DB.prepare(
724
+ "SELECT DISTINCT clause_ref FROM model_nodes WHERE standard = ?1 ORDER BY clause_ref"
725
+ ).bind(entry.package).all();
726
+ const clauses = (c.results ?? []).map((r) => r.clause_ref).filter(Boolean).join(", ");
727
+ return {
728
+ name: "licensed.section",
729
+ query: `${doc} \xA7${clause}`,
730
+ output: `No typed nodes are indexed for ${doc} \xA7${clause}.${clauses ? ` The clauses with typed nodes: ${clauses}.` : ""} State this plainly.`
731
+ };
732
+ }
733
+ return {
734
+ name: "licensed.section",
735
+ query: `${doc} \xA7${clause}`,
736
+ output: JSON.stringify(
737
+ nodes.map((n) => {
738
+ let content = n.content;
739
+ try {
740
+ content = JSON.parse(n.content);
741
+ } catch {
742
+ }
743
+ return { node_id: n.node_id, kind: n.kind, name: n.name, clause: n.clause_ref, content };
744
+ })
745
+ )
746
+ };
747
+ } catch {
748
+ return null;
749
+ }
750
+ }
751
+ };
752
+ var verdictEvaluate = {
753
+ name: "verdict.evaluate",
754
+ description: "Deterministically evaluate a model-plane node's machine checks (OCL boolean expressions, threshold limits) against the quantities a question states. Returns pass/fail with every check's expression and values, or void with the missing parameter names when the question does not state enough. The machine computes; cite the node's clause.",
755
+ params: [
756
+ { key: "node_id", required: true, description: "the model-plane node id, e.g. /req/metrological/repeatability (node ids appear in answers' verdict blocks)" },
757
+ { key: "question", required: true, description: "the statement carrying the quantities, e.g. 'is mpe 0.02 with n_lc 3000 within the limit?'" }
758
+ ],
759
+ audiences: ["mcp"],
760
+ handler: async (env, args) => {
761
+ const node_id = String(args?.node_id ?? "").trim();
762
+ const question = String(args?.question ?? "").trim();
763
+ if (!node_id.startsWith("/") || question.length < 4) return null;
764
+ try {
765
+ const rows = await env.DB.prepare(
766
+ "SELECT standard, kind, name, content FROM model_nodes WHERE node_id = ?1 LIMIT 2"
767
+ ).bind(node_id).all();
768
+ const found = rows.results ?? [];
769
+ if (found.length !== 1) {
770
+ return {
771
+ name: "verdict.evaluate",
772
+ query: node_id,
773
+ output: found.length ? `The node id ${node_id} is indexed under several standards \u2014 name the standard to disambiguate. State this plainly.` : `No model-plane node ${node_id} is indexed. State this plainly.`
774
+ };
775
+ }
776
+ const node = found[0];
777
+ const entry = licensedEntryForPackage(node.standard);
778
+ if (entry) {
779
+ return {
780
+ name: "verdict.evaluate",
781
+ query: node_id,
782
+ output: licenseBoundaryRefusal(entry.doc_number, null) ?? "License boundary \u2014 the node belongs to a licensed standard the caller's entitlement set does not cover."
783
+ };
784
+ }
785
+ let content;
786
+ try {
787
+ content = JSON.parse(node.content);
788
+ } catch {
789
+ content = null;
790
+ }
791
+ const v = evaluate(content, question);
792
+ if (!v) {
793
+ return {
794
+ name: "verdict.evaluate",
795
+ query: node_id,
796
+ output: `The node ${node_id} (${node.kind}) carries no machine-checkable expressions \u2014 it is not evaluatable by the verdict engine. State this plainly.`
797
+ };
798
+ }
799
+ return {
800
+ name: "verdict.evaluate",
801
+ query: node_id,
802
+ output: JSON.stringify({ standard: node.standard, node_id, kind: node.kind, name: node.name, verdict: v.verdict, on_violation: v.on_violation, missing: v.missing, checks: v.checks })
803
+ };
804
+ } catch {
805
+ return null;
806
+ }
807
+ }
808
+ };
809
+ var conditionsCheck = {
810
+ name: "conditions.check",
811
+ description: "Check a stated combination of environmental quantities (temperature, humidity, duration, cycles) against the indexed severity/condition sets \u2014 the pass answer names the matched set and every band, the fail names the nearest set and its distance. Machine evaluation over the condition-set nodes; cite the matched set's clause.",
812
+ params: [
813
+ { key: "question", required: true, description: "the stated combination, e.g. 'damp heat cyclic test at 55 \xB0C for 2 cycles of 24 h'" },
814
+ { key: "standard", required: false, description: "optional scope, the package id, e.g. iec-60068-2-30 (defaults to every indexed condition set the caller may see)" },
815
+ { key: "licensed_standards", required: false, description: "license entitlement keys for licensed condition sets, validated against the deployment's declared licenses" }
816
+ ],
817
+ audiences: ["mcp"],
818
+ handler: async (env, args) => {
819
+ const question = String(args?.question ?? "").trim();
820
+ if (question.length < 4) return null;
821
+ const standard = args?.standard ? String(args.standard).trim() : null;
822
+ const keys = standardKeysFrom({ licensed_standards: args?.licensed_standards });
823
+ try {
824
+ const rows = standard ? await env.DB.prepare("SELECT node_id, standard, content FROM model_nodes WHERE kind = 'condition_set' AND standard = ?1").bind(standard).all() : await env.DB.prepare("SELECT node_id, standard, content FROM model_nodes WHERE kind = 'condition_set'").all();
825
+ const all = (rows.results ?? []).map((r) => {
826
+ let content = r.content;
827
+ try {
828
+ content = JSON.parse(r.content);
829
+ } catch {
830
+ }
831
+ return { node_id: r.node_id, standard: r.standard, content };
832
+ });
833
+ const visible = all.filter((n) => {
834
+ const entry = licensedEntryForPackage(n.standard);
835
+ return !entry || keys.has(entry.key);
836
+ });
837
+ if (!visible.length) {
838
+ return { name: "conditions.check", query: question, output: "No condition sets are indexed (or visible to this caller's entitlements). State this plainly." };
839
+ }
840
+ const v = evaluateConditionSets(visible, question);
841
+ if (!v) {
842
+ return { name: "conditions.check", query: question, output: "No quantities were recognized in the statement \u2014 state the values (temperature, humidity, duration, cycles). The engine checks stated numbers, never guesses." };
843
+ }
844
+ return {
845
+ name: "conditions.check",
846
+ query: question,
847
+ output: JSON.stringify({ verdict: v.verdict, matched: v.matched, checks: v.checks })
848
+ };
849
+ } catch {
850
+ return null;
851
+ }
852
+ }
853
+ };
854
+ var glossaryLookup = {
855
+ name: "glossary.lookup",
856
+ description: "Look up a defined term in the terminology datasets \u2014 the concept's definition and its defining publication. Bind everyday words to the defined term before interpreting a question.",
857
+ params: [{ key: "term", required: true, description: "the term or everyday phrase to bind, e.g. creep or load cell" }],
858
+ audiences: ["mcp"],
859
+ handler: async (env, args) => {
860
+ const term = String(args?.term ?? "").trim();
861
+ if (term.length < 2) return null;
862
+ if (!hasLane(env, "glossary")) return null;
863
+ try {
864
+ const vec = await embed(portModelRunner(env), "", term);
865
+ const cands = await portIndex(env, "glossary").query({ vector: vec, topK: 5 });
866
+ const hits = cands.filter((m) => m.score >= THRESHOLDS.glossaryCosineFloor).map((m) => ({
867
+ term: String(m.metadata?.clause_title ?? "").trim(),
868
+ definition: String(m.metadata?.chunk_text ?? "").split(" \u2014 ").slice(1).join(" \u2014 ").slice(0, 400),
869
+ docidentifier: String(m.metadata?.docidentifier ?? "")
870
+ })).filter((x) => x.term && x.definition);
871
+ if (!hits.length) {
872
+ return { name: "glossary.lookup", query: term, output: `No defined term matches "${term}" in the terminology datasets. State this plainly.` };
873
+ }
874
+ const seen = /* @__PURE__ */ new Set();
875
+ const uniq = hits.filter((h) => {
876
+ const k = h.term.toLowerCase().replace(/[^a-z0-9 ]/g, "").replace(/labeler\b/g, "labeller").replace(/\s+/g, " ").trim();
877
+ if (seen.has(k)) return false;
878
+ seen.add(k);
879
+ return true;
880
+ }).slice(0, 3);
881
+ return {
882
+ name: "glossary.lookup",
883
+ query: term,
884
+ output: uniq.map((h) => `- ${h.term} (${h.docidentifier}): ${h.definition}`).join("\n")
885
+ };
886
+ } catch {
887
+ return null;
888
+ }
889
+ }
890
+ };
891
+
892
+ // workers/worker_public/src/tools.ts
893
+ function parseToolCall(text) {
894
+ const m = /^TOOL\s+([a-z_.]+)\s*(\{[^\n}]*\})?/m.exec(String(text ?? ""));
895
+ if (!m) return null;
896
+ let args = {};
897
+ if (m[2]) {
898
+ try {
899
+ args = JSON.parse(m[2]);
900
+ } catch {
901
+ return null;
902
+ }
903
+ } else if (/^TOOL\s+[a-z_.]+\s*\{/m.test(String(text ?? ""))) {
904
+ return null;
905
+ }
906
+ return { name: m[1].toLowerCase(), args };
907
+ }
908
+ var certificatesSearch = {
909
+ name: "certificates.search",
910
+ description: "Search the certificate register (a snapshot) by holder name, model designation, or a printed certificate number. Returns the matching rows \u2014 number, holder, model, issue year, status, and document links where on file \u2014 or the exact no-match statement for the string asked.",
911
+ params: [{ key: "query", required: true, description: "the holder, model, or printed certificate number to look up" }],
912
+ audiences: ["agent", "mcp"],
913
+ handler: async (env, args) => {
914
+ const query = String(args?.query ?? "").trim().slice(0, 160);
915
+ if (!query) return null;
916
+ const { searchRegister, registerNote, certificateLinks } = await import("./certificates-CO7KX2S2.js");
917
+ const reg = await searchRegister(env.DB, query, true);
918
+ const output = reg?.rows?.length ? [registerNote(reg.rows), certificateLinks(reg.rows)].filter(Boolean).join("\n") : `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.`;
919
+ return { name: "certificates.search", query, output };
920
+ }
921
+ };
922
+ var TOOLS_REGISTRY = [certificatesSearch, unitsGet, graphCites, docsSection, glossaryLookup, documentsFamily, licensedSection, verdictEvaluate, conditionsCheck];
923
+ var TOOL_DECLARATION = [
924
+ "You may use one tool before answering, by writing a single line:",
925
+ ...TOOLS_REGISTRY.filter((t) => t.audiences.includes("agent")).map((t) => {
926
+ const shape = `{${t.params.map((p) => `"${p.key}": "<${p.description}>"`).join(", ")}}`;
927
+ return `TOOL ${t.name} ${shape}`;
928
+ }),
929
+ "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."
930
+ ].join("\n");
931
+ async function runTool(env, call, audience = "agent") {
932
+ const spec = TOOLS_REGISTRY.find((t) => t.name === call.name && t.audiences.includes(audience));
933
+ if (!spec) return null;
934
+ return spec.handler(env, call.args ?? {});
935
+ }
936
+ function toolNote(r) {
937
+ return `The ${r.name} tool returned, for the query "${r.query}":
938
+ ${r.output}`;
939
+ }
940
+
941
+ export {
942
+ standardForDocNumber,
943
+ licensedEntryForPackage,
944
+ licenseBoundaryNote,
945
+ licenseBoundaryRefusal,
946
+ bindModelNode,
947
+ modelGroundingBlock,
948
+ modelCitation,
949
+ modelEcho,
950
+ resolveBlocks,
951
+ contractV2,
952
+ tableRetyped,
953
+ evaluate,
954
+ verdictNote,
955
+ quantitiesIn,
956
+ evaluateConditionSets,
957
+ parseToolCall,
958
+ TOOLS_REGISTRY,
959
+ TOOL_DECLARATION,
960
+ runTool,
961
+ toolNote
962
+ };