@konneal/engine 0.2.169 → 0.2.171
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.
- package/dist/ablate.d.ts +3 -0
- package/dist/ask-4T3E2Z6J.js +16 -0
- package/dist/{chunk-4FZNJR5Q.js → chunk-5UIMQAJZ.js} +10 -0
- package/dist/{chunk-BFOCWZ7U.js → chunk-6KEWBP7O.js} +5 -5
- package/dist/{chunk-LSZTJI7V.js → chunk-KINFFYQH.js} +6 -2
- package/dist/{chunk-NTZX65GT.js → chunk-KKJHJXQV.js} +218 -11
- package/dist/{chunk-QY556RJM.js → chunk-O2XMNKCK.js} +1 -1
- package/dist/{chunk-Y7LWT24U.js → chunk-PQDAL4MX.js} +1 -1
- package/dist/{chunk-PTY2OSC4.js → chunk-QS6V53RO.js} +5 -5
- package/dist/{chunk-LIZJLRXZ.js → chunk-RZLEHCIA.js} +4 -4
- package/dist/{chunk-LU7VIMD7.js → chunk-XWSZWFYP.js} +1 -1
- package/dist/config.d.ts +6 -0
- package/dist/decisionWire.d.ts +25 -0
- package/dist/decisions.d.ts +39 -0
- package/dist/{env-LMHGNJTN.js → env-CNO44VN2.js} +1 -1
- package/dist/search-RNCRT5BR.js +14 -0
- package/dist/{tools-3RP7DHGI.js → tools-HK5RXHBQ.js} +5 -5
- package/dist/worker_mcp/src/index.js +2 -2
- package/dist/worker_public/src/config.js +1 -1
- package/dist/worker_public/src/index.js +11 -11
- package/dist/worker_public/src/requestScope.js +2 -2
- package/package.json +1 -1
- package/workers/worker_public/src/ablate.ts +6 -2
- package/workers/worker_public/src/ask.ts +43 -2
- package/workers/worker_public/src/config.ts +10 -0
- package/workers/worker_public/src/decisionWire.ts +128 -0
- package/workers/worker_public/src/decisions.ts +148 -0
- package/workers/worker_public/src/ports/cloudflare/adapters.ts +10 -2
- package/workers/worker_public/src/ports/model.ts +8 -1
- package/dist/ask-OZO3KHFV.js +0 -16
- package/dist/search-Y4Y46Y57.js +0 -14
package/dist/ablate.d.ts
CHANGED
|
@@ -18,6 +18,9 @@ export interface AblateConfig {
|
|
|
18
18
|
* budget before the answer model reads it. Off in serving; the grid
|
|
19
19
|
* arms it per ask (the row's accuracy-at-token-budget gate). */
|
|
20
20
|
compress: boolean;
|
|
21
|
+
/** The decision pass (TODO.decisions/01): per-request stand-down for
|
|
22
|
+
* the measurement — the serving switch is DECISIONS_ENABLED. */
|
|
23
|
+
noDecisions: boolean;
|
|
21
24
|
}
|
|
22
25
|
export type AblateParse = {
|
|
23
26
|
ok: true;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
handleAsk
|
|
3
|
+
} from "./chunk-KKJHJXQV.js";
|
|
4
|
+
import "./chunk-ECOYO7EX.js";
|
|
5
|
+
import "./chunk-QS6V53RO.js";
|
|
6
|
+
import "./chunk-RZLEHCIA.js";
|
|
7
|
+
import "./chunk-XWSZWFYP.js";
|
|
8
|
+
import "./chunk-O2XMNKCK.js";
|
|
9
|
+
import "./chunk-ETLSWSZ7.js";
|
|
10
|
+
import "./chunk-PQDAL4MX.js";
|
|
11
|
+
import "./chunk-5UIMQAJZ.js";
|
|
12
|
+
import "./chunk-3FYJM7LH.js";
|
|
13
|
+
import "./chunk-KINFFYQH.js";
|
|
14
|
+
export {
|
|
15
|
+
handleAsk
|
|
16
|
+
};
|
|
@@ -15,6 +15,10 @@ var MODELS = {
|
|
|
15
15
|
// vision-capable MoE scores figure IMAGES against figure-seeking
|
|
16
16
|
// questions — one bounded call per figure question, ablatable stage
|
|
17
17
|
vlmFigure: "@cf/deepseek-ai/deepseek-v4.1-flash-1017",
|
|
18
|
+
// the decision pass (TODO.decisions/01): clef-flash gates the
|
|
19
|
+
// requirement-shaped questions, clef decides the derived checklist
|
|
20
|
+
decisionsGate: "@cf/cloudflare/clef-flash",
|
|
21
|
+
decisionsModel: "@cf/cloudflare/clef",
|
|
18
22
|
// hot-path understanding/summarize stays on the cheap Qwen (cost-first lane)
|
|
19
23
|
understand: "@cf/qwen/qwen3-30b-a3b-fp8",
|
|
20
24
|
// the api_call act's intent-to-act mapping (TODO.ai-platform/09) — the
|
|
@@ -93,6 +97,12 @@ var THRESHOLDS = {
|
|
|
93
97
|
// re-query runs at this depth and scopes in code (the native filter is
|
|
94
98
|
// dead — measured 2026-10-05)
|
|
95
99
|
denseStarveK: 100,
|
|
100
|
+
// the decision pass (TODO.decisions): the gate fires at decisionsGateMin
|
|
101
|
+
// noul; the bands assemble met / not clearly stated / not met
|
|
102
|
+
decisionsGateMin: 0.5,
|
|
103
|
+
decisionsMetBand: 0.8,
|
|
104
|
+
decisionsRefuteBand: 0.2,
|
|
105
|
+
decisionsRequirementsMax: 12,
|
|
96
106
|
entailmentGate: true,
|
|
97
107
|
entailmentBudgetMs: 6e3,
|
|
98
108
|
entailmentSupportedFloor: 0.9,
|
|
@@ -6,27 +6,27 @@ import {
|
|
|
6
6
|
sessionFrom,
|
|
7
7
|
telemetry,
|
|
8
8
|
understandQuery
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-RZLEHCIA.js";
|
|
10
10
|
import {
|
|
11
11
|
corsHeaders,
|
|
12
12
|
err,
|
|
13
13
|
json,
|
|
14
14
|
readJson,
|
|
15
15
|
validateQuery
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-O2XMNKCK.js";
|
|
17
17
|
import {
|
|
18
18
|
entitlementScope,
|
|
19
19
|
standardKeysFrom
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-PQDAL4MX.js";
|
|
21
21
|
import {
|
|
22
22
|
LIMITS,
|
|
23
23
|
MODELS,
|
|
24
24
|
num,
|
|
25
25
|
sha256Hex
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-5UIMQAJZ.js";
|
|
27
27
|
import {
|
|
28
28
|
portModelRunner
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-KINFFYQH.js";
|
|
30
30
|
|
|
31
31
|
// workers/worker_public/src/search.ts
|
|
32
32
|
async function handleSearch(env, ctx, req, tier, key) {
|
|
@@ -74,7 +74,7 @@ function cfModelRunner(ai) {
|
|
|
74
74
|
return null;
|
|
75
75
|
},
|
|
76
76
|
async run(req) {
|
|
77
|
-
const
|
|
77
|
+
const payload = req.input !== void 0 ? req.input : {
|
|
78
78
|
messages: req.messages,
|
|
79
79
|
max_tokens: req.maxTokens,
|
|
80
80
|
...req.effort ? { reasoning_effort: req.effort } : {},
|
|
@@ -82,9 +82,13 @@ function cfModelRunner(ai) {
|
|
|
82
82
|
...req.topP != null ? { top_p: req.topP } : {},
|
|
83
83
|
...req.topK != null ? { top_k: req.topK } : {},
|
|
84
84
|
...req.stream ? { stream: true } : {}
|
|
85
|
-
}
|
|
85
|
+
};
|
|
86
|
+
const res = await ai.run(req.model, payload);
|
|
86
87
|
if (req.stream && res && typeof res.getReader === "function") return { text: null, stream: res };
|
|
87
88
|
if (req.stream && res?.body && typeof res.body.getReader === "function") return { text: null, stream: res.body };
|
|
89
|
+
if (res && typeof res === "object" && res.answers && typeof res.answers === "object") {
|
|
90
|
+
return { text: JSON.stringify(res.answers) };
|
|
91
|
+
}
|
|
88
92
|
const text = typeof res?.response === "string" ? res.response : res?.choices?.[0]?.message?.content;
|
|
89
93
|
return { text: typeof text === "string" ? text : null };
|
|
90
94
|
}
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
tableRetyped,
|
|
33
33
|
toolNote,
|
|
34
34
|
verdictNote
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-QS6V53RO.js";
|
|
36
36
|
import {
|
|
37
37
|
NO_CONTEXT,
|
|
38
38
|
STAGE_NAMES,
|
|
@@ -75,18 +75,18 @@ import {
|
|
|
75
75
|
tokenBudget,
|
|
76
76
|
understandQuery,
|
|
77
77
|
usageTotal
|
|
78
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-RZLEHCIA.js";
|
|
79
79
|
import {
|
|
80
80
|
embed,
|
|
81
81
|
generateOnce
|
|
82
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-XWSZWFYP.js";
|
|
83
83
|
import {
|
|
84
84
|
corsHeaders,
|
|
85
85
|
err,
|
|
86
86
|
json,
|
|
87
87
|
readJson,
|
|
88
88
|
validateQuery
|
|
89
|
-
} from "./chunk-
|
|
89
|
+
} from "./chunk-O2XMNKCK.js";
|
|
90
90
|
import {
|
|
91
91
|
cacheableAnswer,
|
|
92
92
|
canonicalRefusal,
|
|
@@ -99,7 +99,7 @@ import {
|
|
|
99
99
|
requestSalt,
|
|
100
100
|
resolveRequestScope,
|
|
101
101
|
standardKeysFrom
|
|
102
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-PQDAL4MX.js";
|
|
103
103
|
import {
|
|
104
104
|
LIMITS,
|
|
105
105
|
MODELS,
|
|
@@ -110,14 +110,14 @@ import {
|
|
|
110
110
|
requestEffort,
|
|
111
111
|
roleModel,
|
|
112
112
|
sha256Hex
|
|
113
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-5UIMQAJZ.js";
|
|
114
114
|
import {
|
|
115
115
|
P
|
|
116
116
|
} from "./chunk-3FYJM7LH.js";
|
|
117
117
|
import {
|
|
118
118
|
portModelRunner,
|
|
119
119
|
portStore
|
|
120
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-KINFFYQH.js";
|
|
121
121
|
|
|
122
122
|
// workers/worker_public/src/internal_gateway.ts
|
|
123
123
|
async function retrieveInternal(service, auth, query) {
|
|
@@ -1404,9 +1404,10 @@ function parseAblate(body, adminToken, presentedToken, knownStages) {
|
|
|
1404
1404
|
const rawRoute = body?.ablate_route;
|
|
1405
1405
|
const speculative = body?.ablate_speculative === true;
|
|
1406
1406
|
const compress = body?.ablate_compress === true;
|
|
1407
|
+
const noDecisions = body?.ablate_no_decisions === true;
|
|
1407
1408
|
const namesAblation = rawStages !== void 0 && rawStages !== null;
|
|
1408
1409
|
const routeAblation = rawRoute !== void 0 && rawRoute !== null && rawRoute !== "adaptive";
|
|
1409
|
-
if (!namesAblation && !noVerdict && !routeAblation && !speculative && !compress) return { ok: true, config: null };
|
|
1410
|
+
if (!namesAblation && !noVerdict && !routeAblation && !speculative && !compress && !noDecisions) return { ok: true, config: null };
|
|
1410
1411
|
if (!adminToken || presentedToken !== adminToken) {
|
|
1411
1412
|
return {
|
|
1412
1413
|
ok: false,
|
|
@@ -1437,7 +1438,188 @@ function parseAblate(body, adminToken, presentedToken, knownStages) {
|
|
|
1437
1438
|
}
|
|
1438
1439
|
stages = [...new Set(rawStages)];
|
|
1439
1440
|
}
|
|
1440
|
-
return { ok: true, config: { stages, noVerdict, route, speculative, compress } };
|
|
1441
|
+
return { ok: true, config: { stages, noVerdict, route, speculative, compress, noDecisions } };
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
// workers/worker_public/src/decisions.ts
|
|
1445
|
+
function parseDerivation(text, cap) {
|
|
1446
|
+
const fallback = { mode: "list", requirements: [] };
|
|
1447
|
+
if (!text) return fallback;
|
|
1448
|
+
const cleaned = text.replace(/```json|```/g, "").trim();
|
|
1449
|
+
const start = cleaned.indexOf("{");
|
|
1450
|
+
const end = cleaned.lastIndexOf("}");
|
|
1451
|
+
if (start === -1 || end <= start) return fallback;
|
|
1452
|
+
let parsed;
|
|
1453
|
+
try {
|
|
1454
|
+
parsed = JSON.parse(cleaned.slice(start, end + 1));
|
|
1455
|
+
} catch {
|
|
1456
|
+
return fallback;
|
|
1457
|
+
}
|
|
1458
|
+
const reqs = Array.isArray(parsed?.requirements) ? parsed.requirements : [];
|
|
1459
|
+
const requirements = [];
|
|
1460
|
+
for (const r of reqs) {
|
|
1461
|
+
const t = typeof r?.text === "string" ? r.text.trim() : "";
|
|
1462
|
+
if (t.length < 8) continue;
|
|
1463
|
+
requirements.push({ text: t.slice(0, 300), clause: typeof r?.clause === "string" ? r.clause.trim().slice(0, 40) : "" });
|
|
1464
|
+
if (requirements.length >= cap) break;
|
|
1465
|
+
}
|
|
1466
|
+
if (!requirements.length) return fallback;
|
|
1467
|
+
const mode = parsed?.mode === "check" ? "check" : "list";
|
|
1468
|
+
return { mode, requirements };
|
|
1469
|
+
}
|
|
1470
|
+
function buildDecisionQuestions(mode, requirements, userQuestion, statedValues) {
|
|
1471
|
+
const questions = {};
|
|
1472
|
+
requirements.forEach((r, i) => {
|
|
1473
|
+
const id = `r${i + 1}`;
|
|
1474
|
+
if (mode === "check") {
|
|
1475
|
+
questions[id] = {
|
|
1476
|
+
type: "noul",
|
|
1477
|
+
instructions: `Requirement: "${r.text}" (clause ${r.clause || "n/a"}). The user asks: "${userQuestion}". Stated values: ${statedValues || "(none stated \u2014 judge whether the state text answers it)"}. Is this requirement met, based only on what the state contains?`,
|
|
1478
|
+
criteria: {
|
|
1479
|
+
true: "the state shows the requirement is satisfied",
|
|
1480
|
+
false: "the state shows it is not satisfied, or the state says nothing about it"
|
|
1481
|
+
}
|
|
1482
|
+
};
|
|
1483
|
+
} else {
|
|
1484
|
+
questions[id] = {
|
|
1485
|
+
type: "noul",
|
|
1486
|
+
instructions: `Is this a genuine, self-contained requirement statement: "${r.text}"?`,
|
|
1487
|
+
criteria: {
|
|
1488
|
+
true: "a real requirement a reader could check",
|
|
1489
|
+
false: "a fragment, duplicate, or not a requirement"
|
|
1490
|
+
}
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
});
|
|
1494
|
+
return questions;
|
|
1495
|
+
}
|
|
1496
|
+
function bandFor(p, metBand, refuteBand) {
|
|
1497
|
+
if (p >= metBand) return "met";
|
|
1498
|
+
if (p <= refuteBand) return "not-met";
|
|
1499
|
+
return "unclear";
|
|
1500
|
+
}
|
|
1501
|
+
function matchAnswers(mode, requirements, answers, metBand, refuteBand) {
|
|
1502
|
+
const items = [];
|
|
1503
|
+
requirements.forEach((r, i) => {
|
|
1504
|
+
const a = answers[`r${i + 1}`];
|
|
1505
|
+
let probability;
|
|
1506
|
+
if (a && a.type === "noul" && typeof a.noul === "number") {
|
|
1507
|
+
probability = a.noul;
|
|
1508
|
+
} else if (a && typeof a === "number") {
|
|
1509
|
+
probability = a;
|
|
1510
|
+
} else {
|
|
1511
|
+
return;
|
|
1512
|
+
}
|
|
1513
|
+
if (probability < 0 || probability > 1) return;
|
|
1514
|
+
items.push({
|
|
1515
|
+
text: r.text,
|
|
1516
|
+
clause: r.clause,
|
|
1517
|
+
band: mode === "check" ? bandFor(probability, metBand, refuteBand) : "met",
|
|
1518
|
+
probability: Math.round(probability * 100) / 100
|
|
1519
|
+
});
|
|
1520
|
+
});
|
|
1521
|
+
return items;
|
|
1522
|
+
}
|
|
1523
|
+
var MARK = { met: "\u2713", "not-met": "\u2717", unclear: "?" };
|
|
1524
|
+
var WORD = { met: "met", "not-met": "not met", unclear: "not clearly stated" };
|
|
1525
|
+
function assembleSection(mode, items) {
|
|
1526
|
+
if (!items.length) return "";
|
|
1527
|
+
const title = mode === "check" ? "Requirements check (automated)" : "Requirements (from the cited clauses)";
|
|
1528
|
+
const lines = items.map((it) => {
|
|
1529
|
+
const mark = mode === "check" ? MARK[it.band] : "\u2022";
|
|
1530
|
+
const clause = it.clause ? ` \u2014 ${it.clause}` : "";
|
|
1531
|
+
const prob = mode === "check" ? ` (${Math.round(it.probability * 100)}%)` : "";
|
|
1532
|
+
return `- ${mark} ${it.text}${clause}${prob}${mode === "check" ? ` \u2014 ${WORD[it.band]}` : ""}`;
|
|
1533
|
+
});
|
|
1534
|
+
return `
|
|
1535
|
+
|
|
1536
|
+
${title}:
|
|
1537
|
+
${lines.join("\n")}`;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
// workers/worker_public/src/decisionWire.ts
|
|
1541
|
+
function decisionsEnabled(env) {
|
|
1542
|
+
return String(env.DECISIONS_ENABLED ?? "true") !== "false";
|
|
1543
|
+
}
|
|
1544
|
+
async function gateQuestion(env, question) {
|
|
1545
|
+
try {
|
|
1546
|
+
const res = await portModelRunner(env).run({
|
|
1547
|
+
model: env.DECISIONS_GATE_MODEL || MODELS.decisionsGate,
|
|
1548
|
+
input: {
|
|
1549
|
+
state: question.slice(0, 500),
|
|
1550
|
+
questions: {
|
|
1551
|
+
requirements: {
|
|
1552
|
+
type: "noul",
|
|
1553
|
+
instructions: "Is this question asking whether requirements are met, or asking what requirements apply to something?",
|
|
1554
|
+
criteria: {
|
|
1555
|
+
true: "the asker wants requirements listed or their own values/products checked against requirements",
|
|
1556
|
+
false: "a definitional, lookup, how-to, or conversational question"
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
},
|
|
1561
|
+
maxTokens: 512
|
|
1562
|
+
});
|
|
1563
|
+
const parsed = JSON.parse(res.text ?? "{}");
|
|
1564
|
+
const p = parsed?.requirements?.noul;
|
|
1565
|
+
return typeof p === "number" ? p : null;
|
|
1566
|
+
} catch {
|
|
1567
|
+
return null;
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
async function runDecisionPass(env, opts) {
|
|
1571
|
+
const gateMin = THRESHOLDS.decisionsGateMin;
|
|
1572
|
+
if (opts.gate == null || opts.gate < gateMin) return null;
|
|
1573
|
+
const passages = opts.passages.filter(Boolean).slice(0, 8).map((p) => p.slice(0, 1600));
|
|
1574
|
+
if (!passages.length) return null;
|
|
1575
|
+
try {
|
|
1576
|
+
const deriveModel = env.DECISIONS_EXTRACT_MODEL || MODELS.member;
|
|
1577
|
+
const derived = await portModelRunner(env).run({
|
|
1578
|
+
model: deriveModel,
|
|
1579
|
+
messages: [
|
|
1580
|
+
{ role: "system", content: "You extract requirement checklists from legal-metrology text. Reply with ONLY JSON, no prose." },
|
|
1581
|
+
{
|
|
1582
|
+
role: "user",
|
|
1583
|
+
content: `User question: ${opts.question}
|
|
1584
|
+
|
|
1585
|
+
` + (opts.statedValues ? `The user's stated values: ${opts.statedValues}
|
|
1586
|
+
|
|
1587
|
+
` : "") + `Passages:
|
|
1588
|
+
${passages.map((p, i) => `[${i + 1}] ${p}`).join("\n")}
|
|
1589
|
+
|
|
1590
|
+
List the DISTINCT requirements relevant to the question as JSON: {"mode":"check"|"list","requirements":[{"text":"...","clause":"..."}]} \u2014 "check" when the user's question or values ask whether requirements are MET; "list" when the user asks what the requirements ARE. Max ${THRESHOLDS.decisionsRequirementsMax}. Each requirement's clause = the clause anchor it comes from. If nothing qualifies, return {"mode":"list","requirements":[]}.`
|
|
1591
|
+
}
|
|
1592
|
+
],
|
|
1593
|
+
maxTokens: 3072,
|
|
1594
|
+
// the GLM law: the effort defaults to MAX when absent — an omitted
|
|
1595
|
+
// effort starved the derivation to empty (observed live: the pass
|
|
1596
|
+
// stood down silently on every fired question)
|
|
1597
|
+
effort: "low",
|
|
1598
|
+
temperature: 0
|
|
1599
|
+
});
|
|
1600
|
+
const { mode, requirements } = parseDerivation(derived.text, THRESHOLDS.decisionsRequirementsMax);
|
|
1601
|
+
if (!requirements.length) return null;
|
|
1602
|
+
const decideModel = env.DECISIONS_MODEL || MODELS.decisionsModel;
|
|
1603
|
+
const decided = await portModelRunner(env).run({
|
|
1604
|
+
model: decideModel,
|
|
1605
|
+
input: {
|
|
1606
|
+
state: `User question: ${opts.question}
|
|
1607
|
+
` + (opts.statedValues ? `Stated values: ${opts.statedValues}
|
|
1608
|
+
` : "") + `Corpus passages:
|
|
1609
|
+
${passages.join("\n")}`.slice(0, 12e3),
|
|
1610
|
+
questions: buildDecisionQuestions(mode, requirements, opts.question, opts.statedValues ?? "")
|
|
1611
|
+
},
|
|
1612
|
+
maxTokens: 4096
|
|
1613
|
+
});
|
|
1614
|
+
const answers = JSON.parse(decided.text ?? "{}");
|
|
1615
|
+
const items = matchAnswers(mode, requirements, answers, THRESHOLDS.decisionsMetBand, THRESHOLDS.decisionsRefuteBand);
|
|
1616
|
+
if (!items.length) return null;
|
|
1617
|
+
const section = assembleSection(mode, items);
|
|
1618
|
+
if (!section) return null;
|
|
1619
|
+
return { mode, gate: opts.gate, items, section };
|
|
1620
|
+
} catch {
|
|
1621
|
+
return null;
|
|
1622
|
+
}
|
|
1441
1623
|
}
|
|
1442
1624
|
|
|
1443
1625
|
// workers/worker_public/src/route.ts
|
|
@@ -2507,6 +2689,8 @@ ${summary}` }] : [],
|
|
|
2507
2689
|
const routeSubset = ablate?.stages ?? (routed.route === "fast" ? fastRouteStages(STAGE_NAMES) : null);
|
|
2508
2690
|
if (routeSubset) console.log("route:", routed.route, routed.features.join("+"), "\u2014", STAGE_NAMES.length - routeSubset.length, "lanes dropped");
|
|
2509
2691
|
const crag = { grade: null, corrective: null };
|
|
2692
|
+
const decisionsArmed = decisionsEnabled(env) && !ablate?.noDecisions;
|
|
2693
|
+
const decisionsGatePromise = decisionsArmed ? gateQuestion(env, q2.query) : Promise.resolve(null);
|
|
2510
2694
|
try {
|
|
2511
2695
|
const tR = Date.now();
|
|
2512
2696
|
if (declaredCtx?.kind === "account") {
|
|
@@ -2646,6 +2830,12 @@ Answer account questions from these records ONLY: name the record when you use i
|
|
|
2646
2830
|
budget,
|
|
2647
2831
|
ablate?.compress === true
|
|
2648
2832
|
);
|
|
2833
|
+
const decisionPromise = decisionsArmed && decisionsGatePromise ? decisionsGatePromise.then((g) => g != null && g >= THRESHOLDS.decisionsGateMin ? runDecisionPass(env, {
|
|
2834
|
+
question: q2.query,
|
|
2835
|
+
gate: g,
|
|
2836
|
+
passages: usedHits.map((h) => h.text),
|
|
2837
|
+
docidentifier: understanding?.docidentifier ?? null
|
|
2838
|
+
}) : null) : Promise.resolve(null);
|
|
2649
2839
|
await attachFigureImages(env, messages, usedHits, q2.query);
|
|
2650
2840
|
const pendingTools = [];
|
|
2651
2841
|
if (multiTurn && env.DB && !nameplate?.manufacturer) {
|
|
@@ -2783,9 +2973,18 @@ Answer account questions from these records ONLY: name the record when you use i
|
|
|
2783
2973
|
}
|
|
2784
2974
|
}
|
|
2785
2975
|
}
|
|
2786
|
-
|
|
2976
|
+
let canonical0 = exciseMisplacedPin(canonicalRefusal(full.replace(/^TOOL [a-z_.]+.*$\n?/gm, "").replace(/^\n+/, ""), refusalScope(answerCites(full))), answerCites(full));
|
|
2787
2977
|
const c2 = canonical0.includes(refusalAnswer()) ? { text: canonical0, blocks: [], dropped: [] } : await contractV2(env.DB, canonical0, usedHits);
|
|
2788
2978
|
let streamedCompletionBlocks = [];
|
|
2979
|
+
if (decisionPromise && !canonical0.includes(refusalAnswer())) {
|
|
2980
|
+
const dp = await decisionPromise;
|
|
2981
|
+
if (dp) {
|
|
2982
|
+
canonical0 += dp.section;
|
|
2983
|
+
send({ type: "token", v: dp.section });
|
|
2984
|
+
full += dp.section;
|
|
2985
|
+
console.log("decisions: streamed the checklist section (" + dp.items.length + " items, mode " + dp.mode + ")");
|
|
2986
|
+
}
|
|
2987
|
+
}
|
|
2789
2988
|
if (!canonical0.includes(refusalAnswer())) {
|
|
2790
2989
|
try {
|
|
2791
2990
|
streamedCompletionBlocks = await completeTables(env.DB, canonical0, usedHits);
|
|
@@ -3017,7 +3216,15 @@ Answer account questions from these records ONLY: name the record when you use i
|
|
|
3017
3216
|
if (v.support !== "supported") console.log("entailment:", v.support, raced.score, raced.ungrounded_claims?.slice(0, 2));
|
|
3018
3217
|
}
|
|
3019
3218
|
}
|
|
3020
|
-
|
|
3219
|
+
let decisionsOut;
|
|
3220
|
+
if (decisionPromise) {
|
|
3221
|
+
const dp = await decisionPromise;
|
|
3222
|
+
if (dp && answer && !answer.includes(refusalAnswer())) {
|
|
3223
|
+
answer = answer + dp.section;
|
|
3224
|
+
decisionsOut = { mode: dp.mode, gate: dp.gate, items: dp.items };
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
const out = { answer, citations: finalCites, ...jsonQuality ? { source_quality: jsonQuality, confidence_note: entailmentNote || qualityNote(jsonQuality), ...entailment ? { entailment } : {}, ...jsonQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(finalCites) } : {} } : {}, model: MODELS.member, query_hash: queryHash, follow_ups: refusalShaped(answer, refusalScope(answerCites(answer))) ? [] : understanding?.follow_ups ?? [], blocks: [...c2ns.blocks, ...verdictBlock ? [verdictBlock] : [], ...conditionBlock ? [conditionBlock] : [], ...aggregationBlock ? [aggregationBlock] : [], ...registerBlock ? [registerBlock] : [], ...completionBlocks], context_applied: ctxApplied, ...liveRecords ? { records: liveRecords } : {}, ...decisionsOut ? { decisions: decisionsOut } : {}, ...ablate ? { ablate } : {}, route: { route: routed.route, features: routed.features } };
|
|
3021
3228
|
const cacheable = !contextual && !declaredCtx && !ablate && cacheableAnswer(answer, refusalScope(answerCites(answer))) && finalAnchors.violations.length === 0;
|
|
3022
3229
|
if (cacheable) {
|
|
3023
3230
|
const ck = exactCacheKey(env.INDEX_VERSION, gen, ns, await sha256Hex(cacheKeyMaterial(q2.query, q2.lang, salt)));
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
embed
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XWSZWFYP.js";
|
|
4
4
|
import {
|
|
5
5
|
standardKeysFrom
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-PQDAL4MX.js";
|
|
7
7
|
import {
|
|
8
8
|
THRESHOLDS
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-5UIMQAJZ.js";
|
|
10
10
|
import {
|
|
11
11
|
P
|
|
12
12
|
} from "./chunk-3FYJM7LH.js";
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
portIndex,
|
|
16
16
|
portModelRunner,
|
|
17
17
|
portStore
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-KINFFYQH.js";
|
|
19
19
|
|
|
20
20
|
// workers/worker_public/src/refs.ts
|
|
21
21
|
var REF = /\[\[(u:(?:u:)?[A-Za-z0-9_-]+)\]\]/g;
|
|
@@ -1509,7 +1509,7 @@ async function runFind(env, args) {
|
|
|
1509
1509
|
};
|
|
1510
1510
|
}
|
|
1511
1511
|
try {
|
|
1512
|
-
const { portStore: portStore2 } = await import("./env-
|
|
1512
|
+
const { portStore: portStore2 } = await import("./env-CNO44VN2.js");
|
|
1513
1513
|
const res = await portStore2(env).prepare(compiled.sql).bind(...compiled.params).all();
|
|
1514
1514
|
const rows = res?.results ?? [];
|
|
1515
1515
|
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.";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
embed,
|
|
3
3
|
rerank
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XWSZWFYP.js";
|
|
5
5
|
import {
|
|
6
6
|
bubbleConfirmPage,
|
|
7
7
|
isAllowedBubbleOrigin
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-O2XMNKCK.js";
|
|
9
9
|
import {
|
|
10
10
|
DATASETS,
|
|
11
11
|
LIMITS,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
processExpansion,
|
|
16
16
|
sha256Hex,
|
|
17
17
|
today
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-5UIMQAJZ.js";
|
|
19
19
|
import {
|
|
20
20
|
P
|
|
21
21
|
} from "./chunk-3FYJM7LH.js";
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
portIndex,
|
|
26
26
|
portModelRunner,
|
|
27
27
|
portStore
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-KINFFYQH.js";
|
|
29
29
|
|
|
30
30
|
// node_modules/@pubid/pubid/dist/grammar/engine.js
|
|
31
31
|
var ParseFailed = class extends Error {
|
package/dist/config.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export declare const MODELS: {
|
|
|
4
4
|
readonly anon: "@cf/zai-org/glm-5.3-flash";
|
|
5
5
|
readonly member: "@cf/zai-org/glm-5.3-flash";
|
|
6
6
|
readonly vlmFigure: "@cf/deepseek-ai/deepseek-v4.1-flash-1017";
|
|
7
|
+
readonly decisionsGate: "@cf/cloudflare/clef-flash";
|
|
8
|
+
readonly decisionsModel: "@cf/cloudflare/clef";
|
|
7
9
|
readonly understand: "@cf/qwen/qwen3-30b-a3b-fp8";
|
|
8
10
|
readonly acts: "@cf/qwen/qwen3-30b-a3b-fp8";
|
|
9
11
|
readonly fallback: "@cf/qwen/qwen3-30b-a3b-fp8";
|
|
@@ -52,6 +54,10 @@ export declare const THRESHOLDS: {
|
|
|
52
54
|
* leaves the source-rung note unchanged). */
|
|
53
55
|
readonly compressShare: 0.6;
|
|
54
56
|
readonly denseStarveK: 100;
|
|
57
|
+
readonly decisionsGateMin: 0.5;
|
|
58
|
+
readonly decisionsMetBand: 0.8;
|
|
59
|
+
readonly decisionsRefuteBand: 0.2;
|
|
60
|
+
readonly decisionsRequirementsMax: 12;
|
|
55
61
|
readonly entailmentGate: true;
|
|
56
62
|
readonly entailmentBudgetMs: 6000;
|
|
57
63
|
readonly entailmentSupportedFloor: 0.9;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type DecisionItem, type DecisionMode } from "./decisions.ts";
|
|
2
|
+
import type { Env } from "./env";
|
|
3
|
+
export interface DecisionPassResult {
|
|
4
|
+
mode: DecisionMode;
|
|
5
|
+
gate: number;
|
|
6
|
+
items: DecisionItem[];
|
|
7
|
+
section: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function decisionsEnabled(env: Env): boolean;
|
|
10
|
+
/** The gate: one clef-flash noul over the question — "is this a
|
|
11
|
+
* requirement-shaped question?" Cheap; prefetched in parallel with
|
|
12
|
+
* retrieval by the caller. Returns the probability, or null on any
|
|
13
|
+
* failure (fail-open: the pass just doesn't fire). */
|
|
14
|
+
export declare function gateQuestion(env: Env, question: string): Promise<number | null>;
|
|
15
|
+
/** The full pass: derive the checklist candidates from the used
|
|
16
|
+
* passages, decide them in one batched Clef call, assemble the
|
|
17
|
+
* deterministic section. Returns null when the pass stands down. */
|
|
18
|
+
export declare function runDecisionPass(env: Env, opts: {
|
|
19
|
+
question: string;
|
|
20
|
+
gate: number;
|
|
21
|
+
passages: string[];
|
|
22
|
+
docidentifier: string | null;
|
|
23
|
+
statedValues?: string;
|
|
24
|
+
userDocs?: boolean;
|
|
25
|
+
}): Promise<DecisionPassResult | null>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface DerivedRequirement {
|
|
2
|
+
text: string;
|
|
3
|
+
clause: string;
|
|
4
|
+
}
|
|
5
|
+
export interface DecisionItem {
|
|
6
|
+
text: string;
|
|
7
|
+
clause: string;
|
|
8
|
+
band: "met" | "not-met" | "unclear";
|
|
9
|
+
probability: number;
|
|
10
|
+
}
|
|
11
|
+
export type DecisionMode = "check" | "list";
|
|
12
|
+
/** Parse the derivation model's reply: JSON with
|
|
13
|
+
* {mode: "check"|"list", requirements: [{text, clause}]}.
|
|
14
|
+
* Tolerant of prose around the JSON, of trailing commas-free objects,
|
|
15
|
+
* and of missing clauses (empty string). Returns [] when nothing
|
|
16
|
+
* sane survives — the pass then stands down. */
|
|
17
|
+
export declare function parseDerivation(text: string | null | undefined, cap: number): {
|
|
18
|
+
mode: DecisionMode;
|
|
19
|
+
requirements: DerivedRequirement[];
|
|
20
|
+
};
|
|
21
|
+
/** Build the Clef questions map from the derived requirements. In
|
|
22
|
+
* "check" mode each requirement becomes a noul (met-or-not given the
|
|
23
|
+
* user's stated values); in "list" mode a noul on whether the
|
|
24
|
+
* requirement is genuinely stated in the corpus text. */
|
|
25
|
+
export declare function buildDecisionQuestions(mode: DecisionMode, requirements: DerivedRequirement[], userQuestion: string, statedValues: string): Record<string, {
|
|
26
|
+
type: "noul";
|
|
27
|
+
instructions: string;
|
|
28
|
+
criteria?: {
|
|
29
|
+
true: string;
|
|
30
|
+
false: string;
|
|
31
|
+
};
|
|
32
|
+
}>;
|
|
33
|
+
export declare function bandFor(p: number, metBand: number, refuteBand: number): DecisionItem["band"];
|
|
34
|
+
/** Match the Clef answers (keyed r1..rN) back onto the requirements and
|
|
35
|
+
* band them. Unmatched/missing answers drop (absence is honest). */
|
|
36
|
+
export declare function matchAnswers(mode: DecisionMode, requirements: DerivedRequirement[], answers: Record<string, any>, metBand: number, refuteBand: number): DecisionItem[];
|
|
37
|
+
/** The deterministic checklist section appended to the answer. The
|
|
38
|
+
* model never writes this — the server composes it from the decisions. */
|
|
39
|
+
export declare function assembleSection(mode: DecisionMode, items: DecisionItem[]): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
handleSearch
|
|
3
|
+
} from "./chunk-6KEWBP7O.js";
|
|
4
|
+
import "./chunk-RZLEHCIA.js";
|
|
5
|
+
import "./chunk-XWSZWFYP.js";
|
|
6
|
+
import "./chunk-O2XMNKCK.js";
|
|
7
|
+
import "./chunk-ETLSWSZ7.js";
|
|
8
|
+
import "./chunk-PQDAL4MX.js";
|
|
9
|
+
import "./chunk-5UIMQAJZ.js";
|
|
10
|
+
import "./chunk-3FYJM7LH.js";
|
|
11
|
+
import "./chunk-KINFFYQH.js";
|
|
12
|
+
export {
|
|
13
|
+
handleSearch
|
|
14
|
+
};
|
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
parseToolCall,
|
|
5
5
|
runTool,
|
|
6
6
|
toolNote
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-QS6V53RO.js";
|
|
8
|
+
import "./chunk-XWSZWFYP.js";
|
|
9
|
+
import "./chunk-PQDAL4MX.js";
|
|
10
|
+
import "./chunk-5UIMQAJZ.js";
|
|
11
11
|
import "./chunk-3FYJM7LH.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-KINFFYQH.js";
|
|
13
13
|
export {
|
|
14
14
|
TOOLS_REGISTRY,
|
|
15
15
|
TOOL_DECLARATION,
|
|
@@ -4,16 +4,16 @@ import {
|
|
|
4
4
|
handleMemories,
|
|
5
5
|
scoreFaithfulness,
|
|
6
6
|
scoreJudge
|
|
7
|
-
} from "../../chunk-
|
|
7
|
+
} from "../../chunk-KKJHJXQV.js";
|
|
8
8
|
import "../../chunk-ECOYO7EX.js";
|
|
9
9
|
import {
|
|
10
10
|
TOOLS_REGISTRY,
|
|
11
11
|
bindModelNode,
|
|
12
12
|
modelGroundingBlock
|
|
13
|
-
} from "../../chunk-
|
|
13
|
+
} from "../../chunk-QS6V53RO.js";
|
|
14
14
|
import {
|
|
15
15
|
handleSearch
|
|
16
|
-
} from "../../chunk-
|
|
16
|
+
} from "../../chunk-6KEWBP7O.js";
|
|
17
17
|
import {
|
|
18
18
|
buildMessages,
|
|
19
19
|
citations,
|
|
@@ -38,11 +38,11 @@ import {
|
|
|
38
38
|
sessionFrom,
|
|
39
39
|
telemetry,
|
|
40
40
|
understandQuery
|
|
41
|
-
} from "../../chunk-
|
|
41
|
+
} from "../../chunk-RZLEHCIA.js";
|
|
42
42
|
import {
|
|
43
43
|
embed,
|
|
44
44
|
generateOnce
|
|
45
|
-
} from "../../chunk-
|
|
45
|
+
} from "../../chunk-XWSZWFYP.js";
|
|
46
46
|
import {
|
|
47
47
|
authenticate,
|
|
48
48
|
corsHeaders,
|
|
@@ -51,14 +51,14 @@ import {
|
|
|
51
51
|
readJson,
|
|
52
52
|
validateQuery,
|
|
53
53
|
withCors
|
|
54
|
-
} from "../../chunk-
|
|
54
|
+
} from "../../chunk-O2XMNKCK.js";
|
|
55
55
|
import {
|
|
56
56
|
canonicalRefusal
|
|
57
57
|
} from "../../chunk-ETLSWSZ7.js";
|
|
58
58
|
import {
|
|
59
59
|
entitlementScope,
|
|
60
60
|
standardKeysFrom
|
|
61
|
-
} from "../../chunk-
|
|
61
|
+
} from "../../chunk-PQDAL4MX.js";
|
|
62
62
|
import {
|
|
63
63
|
LIMITS,
|
|
64
64
|
MODELS,
|
|
@@ -69,7 +69,7 @@ import {
|
|
|
69
69
|
roleModel,
|
|
70
70
|
sha256Hex,
|
|
71
71
|
today
|
|
72
|
-
} from "../../chunk-
|
|
72
|
+
} from "../../chunk-5UIMQAJZ.js";
|
|
73
73
|
import {
|
|
74
74
|
P,
|
|
75
75
|
setProfile
|
|
@@ -77,7 +77,7 @@ import {
|
|
|
77
77
|
import {
|
|
78
78
|
cfBlobs,
|
|
79
79
|
portModelRunner
|
|
80
|
-
} from "../../chunk-
|
|
80
|
+
} from "../../chunk-KINFFYQH.js";
|
|
81
81
|
|
|
82
82
|
// workers/worker_public/src/conversations.ts
|
|
83
83
|
var ID_RE = /^[a-zA-Z0-9_-]{8,64}$/;
|
|
@@ -1119,13 +1119,13 @@ async function callToolOnce(env, ctx, _req, tier, key, name, args, t0) {
|
|
|
1119
1119
|
// stream:false forces the JSON lane (anon defaults to SSE)
|
|
1120
1120
|
body: JSON.stringify({ ...args, stream: false })
|
|
1121
1121
|
});
|
|
1122
|
-
const { runTool, TOOLS_REGISTRY: TOOLS_REGISTRY2 } = await import("../../tools-
|
|
1122
|
+
const { runTool, TOOLS_REGISTRY: TOOLS_REGISTRY2 } = await import("../../tools-HK5RXHBQ.js");
|
|
1123
1123
|
let payload;
|
|
1124
1124
|
if (TOOLS_REGISTRY2.some((t) => t.name === name && t.audiences.includes("mcp"))) {
|
|
1125
1125
|
const r = await runTool({ ...env, DB: env.DB }, { name, args }, "mcp");
|
|
1126
1126
|
payload = r ? { tool: r.name, query: r.query, result: r.output } : { error: { message: `tool ${name} returned nothing for the given arguments` } };
|
|
1127
1127
|
} else {
|
|
1128
|
-
const res = name === "ask" ? await (await import("../../ask-
|
|
1128
|
+
const res = name === "ask" ? await (await import("../../ask-4T3E2Z6J.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-RNCRT5BR.js")).handleSearch(env, ctx, inner, tier, key);
|
|
1129
1129
|
payload = await res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
|
|
1130
1130
|
}
|
|
1131
1131
|
telemetry(env, ctx, tier, `mcp:${name}`, null, !payload?.error, JSON.stringify(payload).length, await sha256Hex(`${name}:${JSON.stringify(args ?? {})}`), void 0, void 0, { durationMs: Date.now() - t0 });
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
requestSalt,
|
|
5
5
|
resolveRequestScope,
|
|
6
6
|
standardKeysFrom
|
|
7
|
-
} from "../../chunk-
|
|
8
|
-
import "../../chunk-
|
|
7
|
+
} from "../../chunk-PQDAL4MX.js";
|
|
8
|
+
import "../../chunk-5UIMQAJZ.js";
|
|
9
9
|
import "../../chunk-3FYJM7LH.js";
|
|
10
10
|
export {
|
|
11
11
|
entitlementScope,
|
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.
|
|
30
|
+
"version": "0.2.171",
|
|
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",
|
|
@@ -39,6 +39,9 @@ export interface AblateConfig {
|
|
|
39
39
|
* budget before the answer model reads it. Off in serving; the grid
|
|
40
40
|
* arms it per ask (the row's accuracy-at-token-budget gate). */
|
|
41
41
|
compress: boolean;
|
|
42
|
+
/** The decision pass (TODO.decisions/01): per-request stand-down for
|
|
43
|
+
* the measurement — the serving switch is DECISIONS_ENABLED. */
|
|
44
|
+
noDecisions: boolean;
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
export type AblateParse =
|
|
@@ -61,10 +64,11 @@ export function parseAblate(
|
|
|
61
64
|
const rawRoute = body?.ablate_route;
|
|
62
65
|
const speculative = body?.ablate_speculative === true;
|
|
63
66
|
const compress = body?.ablate_compress === true;
|
|
67
|
+
const noDecisions = body?.ablate_no_decisions === true;
|
|
64
68
|
const namesAblation = rawStages !== undefined && rawStages !== null;
|
|
65
69
|
const routeAblation = rawRoute !== undefined && rawRoute !== null && rawRoute !== "adaptive";
|
|
66
70
|
|
|
67
|
-
if (!namesAblation && !noVerdict && !routeAblation && !speculative && !compress) return { ok: true, config: null };
|
|
71
|
+
if (!namesAblation && !noVerdict && !routeAblation && !speculative && !compress && !noDecisions) return { ok: true, config: null };
|
|
68
72
|
|
|
69
73
|
if (!adminToken || presentedToken !== adminToken) {
|
|
70
74
|
return {
|
|
@@ -99,5 +103,5 @@ export function parseAblate(
|
|
|
99
103
|
stages = [...new Set(rawStages as string[])];
|
|
100
104
|
}
|
|
101
105
|
|
|
102
|
-
return { ok: true, config: { stages, noVerdict, route, speculative, compress } };
|
|
106
|
+
return { ok: true, config: { stages, noVerdict, route, speculative, compress, noDecisions } };
|
|
103
107
|
}
|
|
@@ -35,6 +35,8 @@ import { entitlementScope, resolveRequestScope, requestSalt, standardKeysFrom }
|
|
|
35
35
|
import { rawSessionToken, type SessionClaims } from "./session";
|
|
36
36
|
import { cacheKeyMaterial, corpusGen, exactCacheKey, freshRequested } from "./answercache";
|
|
37
37
|
import { parseAblate } from "./ablate";
|
|
38
|
+
import { decisionsEnabled, gateQuestion, runDecisionPass } from "./decisionWire";
|
|
39
|
+
import type { DecisionItem } from "./decisions";
|
|
38
40
|
import { STAGE_NAMES } from "./stages/index.ts";
|
|
39
41
|
import { routeFor, fastRouteStages } from "./route.ts";
|
|
40
42
|
import { partitionSubsets, type Partitionable } from "./speculative.ts";
|
|
@@ -1303,6 +1305,11 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1303
1305
|
// report it (TODO.sota/14.6 v2) — the coarse retrieval grade and the
|
|
1304
1306
|
// corrective retry's firing/acceptance
|
|
1305
1307
|
const crag: { grade: string | null; corrective: { fired: boolean; accepted: boolean; grade: string | null } | null } = { grade: null, corrective: null };
|
|
1308
|
+
// the decision pass's gate (TODO.decisions/01): one cheap clef-flash
|
|
1309
|
+
// noul over the question, prefetched in parallel with retrieval — the
|
|
1310
|
+
// pass itself runs only if the gate clears and the ops switch is on
|
|
1311
|
+
const decisionsArmed = decisionsEnabled(env) && !(ablate as any)?.noDecisions;
|
|
1312
|
+
const decisionsGatePromise = decisionsArmed ? gateQuestion(env, q.query) : Promise.resolve(null);
|
|
1306
1313
|
try {
|
|
1307
1314
|
const tR = Date.now();
|
|
1308
1315
|
// ── The "my account" live read (TODO.ai-platform/03) — resolved
|
|
@@ -1502,6 +1509,20 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1502
1509
|
budget,
|
|
1503
1510
|
ablate?.compress === true,
|
|
1504
1511
|
);
|
|
1512
|
+
// the decision pass (TODO.decisions/01): starts here so its calls run
|
|
1513
|
+
// concurrently with generation — the checklist section arrives the
|
|
1514
|
+
// moment the model's last token lands, never delaying the answer
|
|
1515
|
+
const decisionPromise = decisionsArmed && decisionsGatePromise
|
|
1516
|
+
? decisionsGatePromise.then((g) =>
|
|
1517
|
+
g != null && g >= THRESHOLDS.decisionsGateMin
|
|
1518
|
+
? runDecisionPass(env, {
|
|
1519
|
+
question: q.query,
|
|
1520
|
+
gate: g,
|
|
1521
|
+
passages: usedHits.map((h: Hit) => h.text),
|
|
1522
|
+
docidentifier: understanding?.docidentifier ?? null,
|
|
1523
|
+
})
|
|
1524
|
+
: null)
|
|
1525
|
+
: Promise.resolve(null);
|
|
1505
1526
|
await attachFigureImages(env, messages, usedHits, q.query);
|
|
1506
1527
|
// the agent loop (the owner's 2026-09-28 direction): ONE bounded tool
|
|
1507
1528
|
// round, armed only where a tool can help. The model may call
|
|
@@ -1697,7 +1718,7 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1697
1718
|
}
|
|
1698
1719
|
// the misplaced-pin wall rides the streamed path too: a
|
|
1699
1720
|
// CITED stream is not a refusal
|
|
1700
|
-
|
|
1721
|
+
let canonical0 = exciseMisplacedPin(canonicalRefusal(full.replace(/^TOOL [a-z_.]+.*$\n?/gm, "").replace(/^\n+/, ""), refusalScope(answerCites(full))), answerCites(full));
|
|
1701
1722
|
// answer contract v2: validate [[u:]] refs, resolve typed blocks
|
|
1702
1723
|
const c2 = canonical0.includes(refusalAnswer())
|
|
1703
1724
|
? { text: canonical0, blocks: [], dropped: [] as string[] }
|
|
@@ -1707,6 +1728,18 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1707
1728
|
// before): additive D1 reads after the tokens are out, refusal
|
|
1708
1729
|
// answers carry nothing to complete
|
|
1709
1730
|
let streamedCompletionBlocks: Awaited<ReturnType<typeof completeTables>> = [];
|
|
1731
|
+
// the decision pass's section streams as the answer's tail
|
|
1732
|
+
// (the pass ran concurrently with generation — its arrival is
|
|
1733
|
+
// instant here), before the completions and the done event
|
|
1734
|
+
if (decisionPromise && !canonical0.includes(refusalAnswer())) {
|
|
1735
|
+
const dp = await decisionPromise;
|
|
1736
|
+
if (dp) {
|
|
1737
|
+
canonical0 += dp.section;
|
|
1738
|
+
send({ type: "token", v: dp.section });
|
|
1739
|
+
full += dp.section;
|
|
1740
|
+
console.log("decisions: streamed the checklist section (" + dp.items.length + " items, mode " + dp.mode + ")");
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1710
1743
|
if (!canonical0.includes(refusalAnswer())) {
|
|
1711
1744
|
try {
|
|
1712
1745
|
streamedCompletionBlocks = await completeTables(env.DB, canonical0, usedHits);
|
|
@@ -2047,7 +2080,15 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
2047
2080
|
if (v.support !== "supported") console.log("entailment:", v.support, raced!.score, raced!.ungrounded_claims?.slice(0, 2));
|
|
2048
2081
|
}
|
|
2049
2082
|
}
|
|
2050
|
-
|
|
2083
|
+
let decisionsOut: { mode: string; gate: number; items: DecisionItem[] } | undefined;
|
|
2084
|
+
if (decisionPromise) {
|
|
2085
|
+
const dp = await decisionPromise;
|
|
2086
|
+
if (dp && answer && !answer!.includes(refusalAnswer())) {
|
|
2087
|
+
answer = answer! + dp.section;
|
|
2088
|
+
decisionsOut = { mode: dp.mode, gate: dp.gate, items: dp.items };
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
const out = { answer, citations: finalCites, ...(jsonQuality ? { source_quality: jsonQuality!, confidence_note: entailmentNote || qualityNote(jsonQuality!), ...(entailment ? { entailment } : {}), ...(jsonQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(finalCites) } : {}) } : {}), model: MODELS.member, query_hash: queryHash, follow_ups: refusalShaped(answer!, refusalScope(answerCites(answer!))) ? [] : (understanding?.follow_ups ?? []), blocks: [...c2ns.blocks, ...(verdictBlock ? [verdictBlock] : []), ...(conditionBlock ? [conditionBlock] : []), ...(aggregationBlock ? [aggregationBlock] : []), ...(registerBlock ? [registerBlock] : []), ...completionBlocks], context_applied: ctxApplied, ...(liveRecords ? { records: liveRecords } : {}), ...(decisionsOut ? { decisions: decisionsOut } : {}), ...(ablate ? { ablate } : {}), route: { route: routed.route, features: routed.features } };
|
|
2051
2092
|
const cacheable = !contextual && !declaredCtx && !ablate && cacheableAnswer(answer!, refusalScope(answerCites(answer!))) && finalAnchors.violations.length === 0;
|
|
2052
2093
|
if (cacheable) {
|
|
2053
2094
|
const ck = exactCacheKey(env.INDEX_VERSION, gen, ns, await sha256Hex(cacheKeyMaterial(q.query, q.lang, salt)));
|
|
@@ -11,6 +11,10 @@ export const MODELS = {
|
|
|
11
11
|
// vision-capable MoE scores figure IMAGES against figure-seeking
|
|
12
12
|
// questions — one bounded call per figure question, ablatable stage
|
|
13
13
|
vlmFigure: "@cf/deepseek-ai/deepseek-v4.1-flash-1017",
|
|
14
|
+
// the decision pass (TODO.decisions/01): clef-flash gates the
|
|
15
|
+
// requirement-shaped questions, clef decides the derived checklist
|
|
16
|
+
decisionsGate: "@cf/cloudflare/clef-flash",
|
|
17
|
+
decisionsModel: "@cf/cloudflare/clef",
|
|
14
18
|
// hot-path understanding/summarize stays on the cheap Qwen (cost-first lane)
|
|
15
19
|
understand: "@cf/qwen/qwen3-30b-a3b-fp8",
|
|
16
20
|
// the api_call act's intent-to-act mapping (TODO.ai-platform/09) — the
|
|
@@ -90,6 +94,12 @@ export const THRESHOLDS = {
|
|
|
90
94
|
// re-query runs at this depth and scopes in code (the native filter is
|
|
91
95
|
// dead — measured 2026-10-05)
|
|
92
96
|
denseStarveK: 100,
|
|
97
|
+
// the decision pass (TODO.decisions): the gate fires at decisionsGateMin
|
|
98
|
+
// noul; the bands assemble met / not clearly stated / not met
|
|
99
|
+
decisionsGateMin: 0.5,
|
|
100
|
+
decisionsMetBand: 0.8,
|
|
101
|
+
decisionsRefuteBand: 0.2,
|
|
102
|
+
decisionsRequirementsMax: 12,
|
|
93
103
|
entailmentGate: true,
|
|
94
104
|
entailmentBudgetMs: 6000,
|
|
95
105
|
entailmentSupportedFloor: 0.9,
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// The decision pass orchestrator (TODO.decisions/01): gate → derive →
|
|
2
|
+
// decide → hand back the items + the deterministic section. All I/O
|
|
3
|
+
// through the ports; the pure math lives in decisions.ts. Fired only
|
|
4
|
+
// when DECISIONS_ENABLED, not ablated, not a refusal, no verdict block
|
|
5
|
+
// bound, and the gate's noul clears decisionsGateMin.
|
|
6
|
+
import { portModelRunner } from "./env.ts";
|
|
7
|
+
import { MODELS, THRESHOLDS } from "./config.ts";
|
|
8
|
+
import {
|
|
9
|
+
buildDecisionQuestions, matchAnswers, parseDerivation,
|
|
10
|
+
assembleSection, type DecisionItem, type DecisionMode,
|
|
11
|
+
} from "./decisions.ts";
|
|
12
|
+
import type { Env } from "./env";
|
|
13
|
+
|
|
14
|
+
export interface DecisionPassResult {
|
|
15
|
+
mode: DecisionMode;
|
|
16
|
+
gate: number;
|
|
17
|
+
items: DecisionItem[];
|
|
18
|
+
section: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function decisionsEnabled(env: Env): boolean {
|
|
22
|
+
return String((env as any).DECISIONS_ENABLED ?? "true") !== "false";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** The gate: one clef-flash noul over the question — "is this a
|
|
26
|
+
* requirement-shaped question?" Cheap; prefetched in parallel with
|
|
27
|
+
* retrieval by the caller. Returns the probability, or null on any
|
|
28
|
+
* failure (fail-open: the pass just doesn't fire). */
|
|
29
|
+
export async function gateQuestion(env: Env, question: string): Promise<number | null> {
|
|
30
|
+
try {
|
|
31
|
+
const res = await portModelRunner(env).run({
|
|
32
|
+
model: (env as any).DECISIONS_GATE_MODEL || MODELS.decisionsGate,
|
|
33
|
+
input: {
|
|
34
|
+
state: question.slice(0, 500),
|
|
35
|
+
questions: {
|
|
36
|
+
requirements: {
|
|
37
|
+
type: "noul",
|
|
38
|
+
instructions: "Is this question asking whether requirements are met, or asking what requirements apply to something?",
|
|
39
|
+
criteria: {
|
|
40
|
+
true: "the asker wants requirements listed or their own values/products checked against requirements",
|
|
41
|
+
false: "a definitional, lookup, how-to, or conversational question",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
maxTokens: 512,
|
|
47
|
+
});
|
|
48
|
+
const parsed = JSON.parse(res.text ?? "{}") as Record<string, any>;
|
|
49
|
+
const p = parsed?.requirements?.noul;
|
|
50
|
+
return typeof p === "number" ? p : null;
|
|
51
|
+
} catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The full pass: derive the checklist candidates from the used
|
|
57
|
+
* passages, decide them in one batched Clef call, assemble the
|
|
58
|
+
* deterministic section. Returns null when the pass stands down. */
|
|
59
|
+
export async function runDecisionPass(
|
|
60
|
+
env: Env,
|
|
61
|
+
opts: {
|
|
62
|
+
question: string;
|
|
63
|
+
gate: number;
|
|
64
|
+
passages: string[];
|
|
65
|
+
docidentifier: string | null;
|
|
66
|
+
statedValues?: string;
|
|
67
|
+
userDocs?: boolean;
|
|
68
|
+
},
|
|
69
|
+
): Promise<DecisionPassResult | null> {
|
|
70
|
+
const gateMin = THRESHOLDS.decisionsGateMin;
|
|
71
|
+
if (opts.gate == null || opts.gate < gateMin) return null;
|
|
72
|
+
const passages = opts.passages.filter(Boolean).slice(0, 8).map((p) => p.slice(0, 1600));
|
|
73
|
+
if (!passages.length) return null;
|
|
74
|
+
try {
|
|
75
|
+
// 1. derive the checklist candidates from the used passages
|
|
76
|
+
const deriveModel = (env as any).DECISIONS_EXTRACT_MODEL || MODELS.member;
|
|
77
|
+
const derived = await portModelRunner(env).run({
|
|
78
|
+
model: deriveModel,
|
|
79
|
+
messages: [
|
|
80
|
+
{ role: "system", content: "You extract requirement checklists from legal-metrology text. Reply with ONLY JSON, no prose." },
|
|
81
|
+
{
|
|
82
|
+
role: "user",
|
|
83
|
+
content:
|
|
84
|
+
`User question: ${opts.question}\n\n` +
|
|
85
|
+
(opts.statedValues ? `The user's stated values: ${opts.statedValues}\n\n` : "") +
|
|
86
|
+
`Passages:\n${passages.map((p, i) => `[${i + 1}] ${p}`).join("\n")}\n\n` +
|
|
87
|
+
`List the DISTINCT requirements relevant to the question as JSON: ` +
|
|
88
|
+
`{"mode":"check"|"list","requirements":[{"text":"...","clause":"..."}]} — ` +
|
|
89
|
+
`"check" when the user's question or values ask whether requirements are MET; ` +
|
|
90
|
+
`"list" when the user asks what the requirements ARE. Max ${THRESHOLDS.decisionsRequirementsMax}. ` +
|
|
91
|
+
`Each requirement's clause = the clause anchor it comes from. If nothing qualifies, return {"mode":"list","requirements":[]}.`,
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
maxTokens: 3072,
|
|
95
|
+
// the GLM law: the effort defaults to MAX when absent — an omitted
|
|
96
|
+
// effort starved the derivation to empty (observed live: the pass
|
|
97
|
+
// stood down silently on every fired question)
|
|
98
|
+
effort: "low",
|
|
99
|
+
temperature: 0,
|
|
100
|
+
});
|
|
101
|
+
const { mode, requirements } = parseDerivation(derived.text, THRESHOLDS.decisionsRequirementsMax);
|
|
102
|
+
if (!requirements.length) return null;
|
|
103
|
+
|
|
104
|
+
// 2. decide: one batched Clef call over the derived requirements
|
|
105
|
+
const decideModel = (env as any).DECISIONS_MODEL || MODELS.decisionsModel;
|
|
106
|
+
const decided = await portModelRunner(env).run({
|
|
107
|
+
model: decideModel,
|
|
108
|
+
input: {
|
|
109
|
+
state:
|
|
110
|
+
`User question: ${opts.question}\n` +
|
|
111
|
+
(opts.statedValues ? `Stated values: ${opts.statedValues}\n` : "") +
|
|
112
|
+
`Corpus passages:\n${passages.join("\n")}`.slice(0, 12000),
|
|
113
|
+
questions: buildDecisionQuestions(mode, requirements, opts.question, opts.statedValues ?? ""),
|
|
114
|
+
},
|
|
115
|
+
maxTokens: 4096,
|
|
116
|
+
});
|
|
117
|
+
const answers = JSON.parse(decided.text ?? "{}") as Record<string, any>;
|
|
118
|
+
|
|
119
|
+
// 3. band and assemble
|
|
120
|
+
const items = matchAnswers(mode, requirements, answers, THRESHOLDS.decisionsMetBand, THRESHOLDS.decisionsRefuteBand);
|
|
121
|
+
if (!items.length) return null;
|
|
122
|
+
const section = assembleSection(mode, items);
|
|
123
|
+
if (!section) return null;
|
|
124
|
+
return { mode, gate: opts.gate, items, section };
|
|
125
|
+
} catch {
|
|
126
|
+
return null; // additive — the essay answer ships
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// The decision pass core (TODO.decisions/01): requirement-shaped
|
|
2
|
+
// questions are answered as CHECKLISTS, not essays. Pure and
|
|
3
|
+
// dependency-free — the I/O orchestrator (decisionWire.ts) calls these
|
|
4
|
+
// with the model outputs; everything here is deterministic and
|
|
5
|
+
// node-testable. Every failure of the live pass degrades to the essay
|
|
6
|
+
// answer; nothing in this module can break an ask.
|
|
7
|
+
|
|
8
|
+
export interface DerivedRequirement {
|
|
9
|
+
text: string;
|
|
10
|
+
clause: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface DecisionItem {
|
|
14
|
+
text: string;
|
|
15
|
+
clause: string;
|
|
16
|
+
band: "met" | "not-met" | "unclear";
|
|
17
|
+
probability: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type DecisionMode = "check" | "list";
|
|
21
|
+
|
|
22
|
+
/** Parse the derivation model's reply: JSON with
|
|
23
|
+
* {mode: "check"|"list", requirements: [{text, clause}]}.
|
|
24
|
+
* Tolerant of prose around the JSON, of trailing commas-free objects,
|
|
25
|
+
* and of missing clauses (empty string). Returns [] when nothing
|
|
26
|
+
* sane survives — the pass then stands down. */
|
|
27
|
+
export function parseDerivation(text: string | null | undefined, cap: number): {
|
|
28
|
+
mode: DecisionMode;
|
|
29
|
+
requirements: DerivedRequirement[];
|
|
30
|
+
} {
|
|
31
|
+
const fallback = { mode: "list" as DecisionMode, requirements: [] as DerivedRequirement[] };
|
|
32
|
+
if (!text) return fallback;
|
|
33
|
+
const cleaned = text.replace(/```json|```/g, "").trim();
|
|
34
|
+
const start = cleaned.indexOf("{");
|
|
35
|
+
const end = cleaned.lastIndexOf("}");
|
|
36
|
+
if (start === -1 || end <= start) return fallback;
|
|
37
|
+
let parsed: any;
|
|
38
|
+
try {
|
|
39
|
+
parsed = JSON.parse(cleaned.slice(start, end + 1));
|
|
40
|
+
} catch {
|
|
41
|
+
return fallback;
|
|
42
|
+
}
|
|
43
|
+
const reqs = Array.isArray(parsed?.requirements) ? parsed.requirements : [];
|
|
44
|
+
const requirements: DerivedRequirement[] = [];
|
|
45
|
+
for (const r of reqs) {
|
|
46
|
+
const t = typeof r?.text === "string" ? r.text.trim() : "";
|
|
47
|
+
if (t.length < 8) continue;
|
|
48
|
+
requirements.push({ text: t.slice(0, 300), clause: typeof r?.clause === "string" ? r.clause.trim().slice(0, 40) : "" });
|
|
49
|
+
if (requirements.length >= cap) break;
|
|
50
|
+
}
|
|
51
|
+
if (!requirements.length) return fallback;
|
|
52
|
+
const mode: DecisionMode = parsed?.mode === "check" ? "check" : "list";
|
|
53
|
+
return { mode, requirements };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Build the Clef questions map from the derived requirements. In
|
|
57
|
+
* "check" mode each requirement becomes a noul (met-or-not given the
|
|
58
|
+
* user's stated values); in "list" mode a noul on whether the
|
|
59
|
+
* requirement is genuinely stated in the corpus text. */
|
|
60
|
+
export function buildDecisionQuestions(
|
|
61
|
+
mode: DecisionMode,
|
|
62
|
+
requirements: DerivedRequirement[],
|
|
63
|
+
userQuestion: string,
|
|
64
|
+
statedValues: string,
|
|
65
|
+
): Record<string, { type: "noul"; instructions: string; criteria?: { true: string; false: string } }> {
|
|
66
|
+
const questions: Record<string, { type: "noul"; instructions: string; criteria?: { true: string; false: string } }> = {};
|
|
67
|
+
requirements.forEach((r, i) => {
|
|
68
|
+
const id = `r${i + 1}`;
|
|
69
|
+
if (mode === "check") {
|
|
70
|
+
questions[id] = {
|
|
71
|
+
type: "noul",
|
|
72
|
+
instructions:
|
|
73
|
+
`Requirement: "${r.text}" (clause ${r.clause || "n/a"}). ` +
|
|
74
|
+
`The user asks: "${userQuestion}". ` +
|
|
75
|
+
`Stated values: ${statedValues || "(none stated — judge whether the state text answers it)"}. ` +
|
|
76
|
+
`Is this requirement met, based only on what the state contains?`,
|
|
77
|
+
criteria: {
|
|
78
|
+
true: "the state shows the requirement is satisfied",
|
|
79
|
+
false: "the state shows it is not satisfied, or the state says nothing about it",
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
} else {
|
|
83
|
+
questions[id] = {
|
|
84
|
+
type: "noul",
|
|
85
|
+
instructions: `Is this a genuine, self-contained requirement statement: "${r.text}"?`,
|
|
86
|
+
criteria: {
|
|
87
|
+
true: "a real requirement a reader could check",
|
|
88
|
+
false: "a fragment, duplicate, or not a requirement",
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
return questions;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function bandFor(p: number, metBand: number, refuteBand: number): DecisionItem["band"] {
|
|
97
|
+
if (p >= metBand) return "met";
|
|
98
|
+
if (p <= refuteBand) return "not-met";
|
|
99
|
+
return "unclear";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Match the Clef answers (keyed r1..rN) back onto the requirements and
|
|
103
|
+
* band them. Unmatched/missing answers drop (absence is honest). */
|
|
104
|
+
export function matchAnswers(
|
|
105
|
+
mode: DecisionMode,
|
|
106
|
+
requirements: DerivedRequirement[],
|
|
107
|
+
answers: Record<string, any>,
|
|
108
|
+
metBand: number,
|
|
109
|
+
refuteBand: number,
|
|
110
|
+
): DecisionItem[] {
|
|
111
|
+
const items: DecisionItem[] = [];
|
|
112
|
+
requirements.forEach((r, i) => {
|
|
113
|
+
const a = answers[`r${i + 1}`];
|
|
114
|
+
let probability: number;
|
|
115
|
+
if (a && a.type === "noul" && typeof a.noul === "number") {
|
|
116
|
+
probability = a.noul;
|
|
117
|
+
} else if (a && typeof a === "number") {
|
|
118
|
+
probability = a;
|
|
119
|
+
} else {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (probability < 0 || probability > 1) return;
|
|
123
|
+
items.push({
|
|
124
|
+
text: r.text,
|
|
125
|
+
clause: r.clause,
|
|
126
|
+
band: mode === "check" ? bandFor(probability, metBand, refuteBand) : "met",
|
|
127
|
+
probability: Math.round(probability * 100) / 100,
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
return items;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const MARK: Record<DecisionItem["band"], string> = { met: "✓", "not-met": "✗", unclear: "?" };
|
|
134
|
+
const WORD: Record<DecisionItem["band"], string> = { met: "met", "not-met": "not met", unclear: "not clearly stated" };
|
|
135
|
+
|
|
136
|
+
/** The deterministic checklist section appended to the answer. The
|
|
137
|
+
* model never writes this — the server composes it from the decisions. */
|
|
138
|
+
export function assembleSection(mode: DecisionMode, items: DecisionItem[]): string {
|
|
139
|
+
if (!items.length) return "";
|
|
140
|
+
const title = mode === "check" ? "Requirements check (automated)" : "Requirements (from the cited clauses)";
|
|
141
|
+
const lines = items.map((it) => {
|
|
142
|
+
const mark = mode === "check" ? MARK[it.band] : "•";
|
|
143
|
+
const clause = it.clause ? ` — ${it.clause}` : "";
|
|
144
|
+
const prob = mode === "check" ? ` (${Math.round(it.probability * 100)}%)` : "";
|
|
145
|
+
return `- ${mark} ${it.text}${clause}${prob}${mode === "check" ? ` — ${WORD[it.band]}` : ""}`;
|
|
146
|
+
});
|
|
147
|
+
return `\n\n${title}:\n${lines.join("\n")}`;
|
|
148
|
+
}
|
|
@@ -101,7 +101,9 @@ export function cfModelRunner(ai: unknown): ModelRunner {
|
|
|
101
101
|
return null;
|
|
102
102
|
},
|
|
103
103
|
async run(req: GenerateRequest): Promise<GenerateResult> {
|
|
104
|
-
|
|
104
|
+
// the decision models' native shape ({state, questions}) passes
|
|
105
|
+
// through verbatim — the adapter adds no sampling shaping to it
|
|
106
|
+
const payload: any = req.input !== undefined ? req.input : {
|
|
105
107
|
messages: req.messages,
|
|
106
108
|
max_tokens: req.maxTokens,
|
|
107
109
|
...(req.effort ? { reasoning_effort: req.effort } : {}),
|
|
@@ -109,9 +111,15 @@ export function cfModelRunner(ai: unknown): ModelRunner {
|
|
|
109
111
|
...(req.topP != null ? { top_p: req.topP } : {}),
|
|
110
112
|
...(req.topK != null ? { top_k: req.topK } : {}),
|
|
111
113
|
...(req.stream ? { stream: true } : {}),
|
|
112
|
-
}
|
|
114
|
+
};
|
|
115
|
+
const res: any = await (ai as any).run(req.model, payload);
|
|
113
116
|
if (req.stream && res && typeof res.getReader === "function") return { text: null, stream: res };
|
|
114
117
|
if (req.stream && res?.body && typeof res.body.getReader === "function") return { text: null, stream: res.body };
|
|
118
|
+
// the decision models answer with a typed answers object — the
|
|
119
|
+
// lossless form is its JSON, which the caller parses
|
|
120
|
+
if (res && typeof res === "object" && res.answers && typeof res.answers === "object") {
|
|
121
|
+
return { text: JSON.stringify(res.answers) };
|
|
122
|
+
}
|
|
115
123
|
const text = typeof res?.response === "string" ? res.response : res?.choices?.[0]?.message?.content;
|
|
116
124
|
return { text: typeof text === "string" ? text : null };
|
|
117
125
|
},
|
|
@@ -6,7 +6,14 @@
|
|
|
6
6
|
* multi-SDO / multi-cloud: docs/konneal-extraction-plan.md §5. */
|
|
7
7
|
export interface GenerateRequest {
|
|
8
8
|
model: string;
|
|
9
|
-
messages
|
|
9
|
+
/** The messages payload — required unless `input` carries a native
|
|
10
|
+
* non-messages shape (the decision models). */
|
|
11
|
+
messages?: unknown[];
|
|
12
|
+
/** Native-shape passthrough for models whose contract is not
|
|
13
|
+
* messages-based (the decision models: {state, questions}). When
|
|
14
|
+
* present it REPLACES the messages payload verbatim — the adapter
|
|
15
|
+
* adds no sampling shaping. */
|
|
16
|
+
input?: unknown;
|
|
10
17
|
effort?: string;
|
|
11
18
|
maxTokens?: number;
|
|
12
19
|
temperature?: number;
|
package/dist/ask-OZO3KHFV.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
handleAsk
|
|
3
|
-
} from "./chunk-NTZX65GT.js";
|
|
4
|
-
import "./chunk-ECOYO7EX.js";
|
|
5
|
-
import "./chunk-PTY2OSC4.js";
|
|
6
|
-
import "./chunk-LIZJLRXZ.js";
|
|
7
|
-
import "./chunk-LU7VIMD7.js";
|
|
8
|
-
import "./chunk-QY556RJM.js";
|
|
9
|
-
import "./chunk-ETLSWSZ7.js";
|
|
10
|
-
import "./chunk-Y7LWT24U.js";
|
|
11
|
-
import "./chunk-4FZNJR5Q.js";
|
|
12
|
-
import "./chunk-3FYJM7LH.js";
|
|
13
|
-
import "./chunk-LSZTJI7V.js";
|
|
14
|
-
export {
|
|
15
|
-
handleAsk
|
|
16
|
-
};
|
package/dist/search-Y4Y46Y57.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
handleSearch
|
|
3
|
-
} from "./chunk-BFOCWZ7U.js";
|
|
4
|
-
import "./chunk-LIZJLRXZ.js";
|
|
5
|
-
import "./chunk-LU7VIMD7.js";
|
|
6
|
-
import "./chunk-QY556RJM.js";
|
|
7
|
-
import "./chunk-ETLSWSZ7.js";
|
|
8
|
-
import "./chunk-Y7LWT24U.js";
|
|
9
|
-
import "./chunk-4FZNJR5Q.js";
|
|
10
|
-
import "./chunk-3FYJM7LH.js";
|
|
11
|
-
import "./chunk-LSZTJI7V.js";
|
|
12
|
-
export {
|
|
13
|
-
handleSearch
|
|
14
|
-
};
|