@konneal/engine 0.2.170 → 0.2.175
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/admin.d.ts +5 -3
- package/dist/ask-7TNQCRD6.js +16 -0
- package/dist/{chunk-QS6V53RO.js → chunk-B2MU4ZWM.js} +3 -3
- package/dist/{chunk-RZLEHCIA.js → chunk-CLDMP5YH.js} +3 -3
- package/dist/{chunk-O2XMNKCK.js → chunk-D7MO4RVQ.js} +1 -1
- package/dist/{chunk-PQDAL4MX.js → chunk-FNQ7UOEB.js} +1 -1
- package/dist/{chunk-5UIMQAJZ.js → chunk-HWWJAJWM.js} +7 -0
- package/dist/{chunk-6KEWBP7O.js → chunk-MUWO2EV6.js} +4 -4
- package/dist/{chunk-XWSZWFYP.js → chunk-ZHT4456M.js} +1 -1
- package/dist/{chunk-PO3UBDNZ.js → chunk-ZZLUGHZ2.js} +27 -9
- package/dist/config.d.ts +2 -0
- package/dist/decisionWire.d.ts +15 -0
- package/dist/openapi-surface.gen.d.ts +1 -1
- package/dist/openapi-types.d.ts +54 -1
- package/dist/search-KNPPTHMG.js +14 -0
- package/dist/{tools-HK5RXHBQ.js → tools-VHN54DWH.js} +4 -4
- 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 +90 -28
- package/dist/worker_public/src/requestScope.js +2 -2
- package/package.json +1 -1
- package/workers/worker_public/openapi.yaml +39 -1
- package/workers/worker_public/src/admin.ts +84 -20
- package/workers/worker_public/src/ask.ts +12 -5
- package/workers/worker_public/src/config.ts +7 -0
- package/workers/worker_public/src/decisionWire.ts +30 -1
- package/workers/worker_public/src/index.ts +2 -1
- package/workers/worker_public/src/openapi-surface.gen.ts +6 -0
- package/dist/ask-BKWQEMSY.js +0 -16
- package/dist/search-RNCRT5BR.js +0 -14
package/dist/admin.d.ts
CHANGED
|
@@ -21,9 +21,11 @@ export declare function handleSectionUnit(env: Env, ctx: ExecutionContext, req:
|
|
|
21
21
|
* the deterministic registry line. Admin-gated; idempotent (force
|
|
22
22
|
* regenerates); the quality-first lane pays once. */
|
|
23
23
|
export declare function handleFamilySummary(env: Env, req: Request): Promise<Response>;
|
|
24
|
-
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
/** The pairwise vision judge (TODO.sota/18.4's A/B): two anonymized
|
|
25
|
+
* captions of the SAME figure, presented in randomized order beside the
|
|
26
|
+
* image itself; a THIRD model (never a contestant) picks the better
|
|
27
|
+
* caption with a reason. Admin-gated; one-time quality-first lane. */
|
|
28
|
+
export declare function handleVisionJudge(env: Env, req: Request): Promise<Response>;
|
|
27
29
|
/** One-time figure captioning (TODO.remaining/03): fetch the unit's asset
|
|
28
30
|
* from R2, describe it with the vision-capable answer model, store the
|
|
29
31
|
* description into unit_payloads. Admin-gated; idempotent. */
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
handleAsk
|
|
3
|
+
} from "./chunk-ZZLUGHZ2.js";
|
|
4
|
+
import "./chunk-ECOYO7EX.js";
|
|
5
|
+
import "./chunk-B2MU4ZWM.js";
|
|
6
|
+
import "./chunk-CLDMP5YH.js";
|
|
7
|
+
import "./chunk-ZHT4456M.js";
|
|
8
|
+
import "./chunk-D7MO4RVQ.js";
|
|
9
|
+
import "./chunk-ETLSWSZ7.js";
|
|
10
|
+
import "./chunk-FNQ7UOEB.js";
|
|
11
|
+
import "./chunk-HWWJAJWM.js";
|
|
12
|
+
import "./chunk-3FYJM7LH.js";
|
|
13
|
+
import "./chunk-KINFFYQH.js";
|
|
14
|
+
export {
|
|
15
|
+
handleAsk
|
|
16
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
embed
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ZHT4456M.js";
|
|
4
4
|
import {
|
|
5
5
|
standardKeysFrom
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-FNQ7UOEB.js";
|
|
7
7
|
import {
|
|
8
8
|
THRESHOLDS
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-HWWJAJWM.js";
|
|
10
10
|
import {
|
|
11
11
|
P
|
|
12
12
|
} from "./chunk-3FYJM7LH.js";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
embed,
|
|
3
3
|
rerank
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZHT4456M.js";
|
|
5
5
|
import {
|
|
6
6
|
bubbleConfirmPage,
|
|
7
7
|
isAllowedBubbleOrigin
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-D7MO4RVQ.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-HWWJAJWM.js";
|
|
19
19
|
import {
|
|
20
20
|
P
|
|
21
21
|
} from "./chunk-3FYJM7LH.js";
|
|
@@ -11,6 +11,13 @@ var MODELS = {
|
|
|
11
11
|
// Vision image-parts land with answer contract v2; text answers work now.
|
|
12
12
|
anon: "@cf/zai-org/glm-5.3-flash",
|
|
13
13
|
member: "@cf/zai-org/glm-5.3-flash",
|
|
14
|
+
// figure captions + the vision lane (one-time, quality-first; the A/B
|
|
15
|
+
// lever is CAPTION_MODEL, the per-request arm is the admin route's
|
|
16
|
+
// body.model)
|
|
17
|
+
caption: "@cf/zai-org/glm-5.3-flash",
|
|
18
|
+
// the pairwise vision judge (sees the image; a THIRD model never
|
|
19
|
+
// judges its own arm)
|
|
20
|
+
visionJudge: "@cf/deepseek-ai/deepseek-v4.1-flash-1017",
|
|
14
21
|
// the VLM figure rerank (TODO.sota/18.3): the newly-landed
|
|
15
22
|
// vision-capable MoE scores figure IMAGES against figure-seeking
|
|
16
23
|
// questions — one bounded call per figure question, ablatable stage
|
|
@@ -6,24 +6,24 @@ import {
|
|
|
6
6
|
sessionFrom,
|
|
7
7
|
telemetry,
|
|
8
8
|
understandQuery
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-CLDMP5YH.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-D7MO4RVQ.js";
|
|
17
17
|
import {
|
|
18
18
|
entitlementScope,
|
|
19
19
|
standardKeysFrom
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-FNQ7UOEB.js";
|
|
21
21
|
import {
|
|
22
22
|
LIMITS,
|
|
23
23
|
MODELS,
|
|
24
24
|
num,
|
|
25
25
|
sha256Hex
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-HWWJAJWM.js";
|
|
27
27
|
import {
|
|
28
28
|
portModelRunner
|
|
29
29
|
} from "./chunk-KINFFYQH.js";
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
tableRetyped,
|
|
33
33
|
toolNote,
|
|
34
34
|
verdictNote
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-B2MU4ZWM.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-CLDMP5YH.js";
|
|
79
79
|
import {
|
|
80
80
|
embed,
|
|
81
81
|
generateOnce
|
|
82
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-ZHT4456M.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-D7MO4RVQ.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-FNQ7UOEB.js";
|
|
103
103
|
import {
|
|
104
104
|
LIMITS,
|
|
105
105
|
MODELS,
|
|
@@ -110,7 +110,7 @@ import {
|
|
|
110
110
|
requestEffort,
|
|
111
111
|
roleModel,
|
|
112
112
|
sha256Hex
|
|
113
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-HWWJAJWM.js";
|
|
114
114
|
import {
|
|
115
115
|
P
|
|
116
116
|
} from "./chunk-3FYJM7LH.js";
|
|
@@ -1590,7 +1590,11 @@ ${passages.map((p, i) => `[${i + 1}] ${p}`).join("\n")}
|
|
|
1590
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
1591
|
}
|
|
1592
1592
|
],
|
|
1593
|
-
maxTokens:
|
|
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",
|
|
1594
1598
|
temperature: 0
|
|
1595
1599
|
});
|
|
1596
1600
|
const { mode, requirements } = parseDerivation(derived.text, THRESHOLDS.decisionsRequirementsMax);
|
|
@@ -1617,6 +1621,15 @@ ${passages.join("\n")}`.slice(0, 12e3),
|
|
|
1617
1621
|
return null;
|
|
1618
1622
|
}
|
|
1619
1623
|
}
|
|
1624
|
+
function telemetryDecisions(env, ctx, tier, queryHash, result, durationMs) {
|
|
1625
|
+
try {
|
|
1626
|
+
telemetry(env, ctx, tier, "ask-decisions", result ? result.gate.toFixed(2) : "0", !!result, result?.items.length ?? 0, queryHash, result?.mode ?? void 0, void 0, { durationMs });
|
|
1627
|
+
for (const it of result?.items ?? []) {
|
|
1628
|
+
telemetry(env, ctx, tier, "ask-decision", it.probability.toFixed(2), it.band === "met", 1, queryHash, it.band, void 0, {});
|
|
1629
|
+
}
|
|
1630
|
+
} catch {
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1620
1633
|
|
|
1621
1634
|
// workers/worker_public/src/route.ts
|
|
1622
1635
|
var ROUTE_FAST_WORD_CAP = 10;
|
|
@@ -2972,14 +2985,17 @@ Answer account questions from these records ONLY: name the record when you use i
|
|
|
2972
2985
|
let canonical0 = exciseMisplacedPin(canonicalRefusal(full.replace(/^TOOL [a-z_.]+.*$\n?/gm, "").replace(/^\n+/, ""), refusalScope(answerCites(full))), answerCites(full));
|
|
2973
2986
|
const c2 = canonical0.includes(refusalAnswer()) ? { text: canonical0, blocks: [], dropped: [] } : await contractV2(env.DB, canonical0, usedHits);
|
|
2974
2987
|
let streamedCompletionBlocks = [];
|
|
2975
|
-
|
|
2988
|
+
let streamedDecisions;
|
|
2989
|
+
if (decisionPromise && !canonical0.includes(refusalAnswer()) && !verdictBlock && !conditionBlock && !aggregationBlock) {
|
|
2976
2990
|
const dp = await decisionPromise;
|
|
2977
2991
|
if (dp) {
|
|
2978
2992
|
canonical0 += dp.section;
|
|
2979
2993
|
send({ type: "token", v: dp.section });
|
|
2980
2994
|
full += dp.section;
|
|
2995
|
+
streamedDecisions = { mode: dp.mode, gate: dp.gate, items: dp.items };
|
|
2981
2996
|
console.log("decisions: streamed the checklist section (" + dp.items.length + " items, mode " + dp.mode + ")");
|
|
2982
2997
|
}
|
|
2998
|
+
telemetryDecisions(env, ctx, tier, queryHash, streamedDecisions ?? null, Date.now() - tStart);
|
|
2983
2999
|
}
|
|
2984
3000
|
if (!canonical0.includes(refusalAnswer())) {
|
|
2985
3001
|
try {
|
|
@@ -2994,6 +3010,7 @@ Answer account questions from these records ONLY: name the record when you use i
|
|
|
2994
3010
|
model,
|
|
2995
3011
|
query_hash: queryHash,
|
|
2996
3012
|
follow_ups: refusalShaped(canonical0, refusalScope(answerCites(full))) ? [] : understanding?.follow_ups ?? [],
|
|
3013
|
+
...streamedDecisions ? { decisions: streamedDecisions } : {},
|
|
2997
3014
|
blocks: [...c2.blocks, ...verdictBlock ? [verdictBlock] : [], ...conditionBlock ? [conditionBlock] : [], ...aggregationBlock ? [aggregationBlock] : [], ...streamedCompletionBlocks],
|
|
2998
3015
|
context_applied: ctxApplied,
|
|
2999
3016
|
read: readAs(),
|
|
@@ -3215,10 +3232,11 @@ Answer account questions from these records ONLY: name the record when you use i
|
|
|
3215
3232
|
let decisionsOut;
|
|
3216
3233
|
if (decisionPromise) {
|
|
3217
3234
|
const dp = await decisionPromise;
|
|
3218
|
-
if (dp && answer && !answer.includes(refusalAnswer())) {
|
|
3235
|
+
if (dp && answer && !answer.includes(refusalAnswer()) && !verdictBlock && !conditionBlock && !aggregationBlock) {
|
|
3219
3236
|
answer = answer + dp.section;
|
|
3220
3237
|
decisionsOut = { mode: dp.mode, gate: dp.gate, items: dp.items };
|
|
3221
3238
|
}
|
|
3239
|
+
telemetryDecisions(env, ctx, tier, queryHash, decisionsOut ?? null, Date.now() - tStart);
|
|
3222
3240
|
}
|
|
3223
3241
|
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 } };
|
|
3224
3242
|
const cacheable = !contextual && !declaredCtx && !ablate && cacheableAnswer(answer, refusalScope(answerCites(answer))) && finalAnchors.violations.length === 0;
|
package/dist/config.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export declare const MODELS: {
|
|
|
3
3
|
readonly rerank: "@cf/baai/bge-reranker-base";
|
|
4
4
|
readonly anon: "@cf/zai-org/glm-5.3-flash";
|
|
5
5
|
readonly member: "@cf/zai-org/glm-5.3-flash";
|
|
6
|
+
readonly caption: "@cf/zai-org/glm-5.3-flash";
|
|
7
|
+
readonly visionJudge: "@cf/deepseek-ai/deepseek-v4.1-flash-1017";
|
|
6
8
|
readonly vlmFigure: "@cf/deepseek-ai/deepseek-v4.1-flash-1017";
|
|
7
9
|
readonly decisionsGate: "@cf/cloudflare/clef-flash";
|
|
8
10
|
readonly decisionsModel: "@cf/cloudflare/clef";
|
package/dist/decisionWire.d.ts
CHANGED
|
@@ -23,3 +23,18 @@ export declare function runDecisionPass(env: Env, opts: {
|
|
|
23
23
|
statedValues?: string;
|
|
24
24
|
userDocs?: boolean;
|
|
25
25
|
}): Promise<DecisionPassResult | null>;
|
|
26
|
+
/** The decisions telemetry (TODO.decisions/03): the nightly's
|
|
27
|
+
* calibration signal, riding the queries table's route key with a
|
|
28
|
+
* defined encoding — no schema migration.
|
|
29
|
+
* - one PASS row, route "ask-decisions": ok = fired, lang = mode,
|
|
30
|
+
* model = the gate probability (2dp), duration_ms = the pass's.
|
|
31
|
+
* - one ITEM row per requirement, route "ask-decision": ok = band is
|
|
32
|
+
* "met", lang = band, model = the probability (2dp); query_hash
|
|
33
|
+
* joins the rows to their pass. */
|
|
34
|
+
export declare function telemetryDecisions(env: Env, ctx: {
|
|
35
|
+
waitUntil(p: Promise<unknown>): void;
|
|
36
|
+
}, tier: string, queryHash: string, result: {
|
|
37
|
+
mode: string;
|
|
38
|
+
gate: number;
|
|
39
|
+
items: DecisionItem[];
|
|
40
|
+
} | null, durationMs: number): void;
|
|
@@ -3,7 +3,7 @@ export interface OpenApiRoute {
|
|
|
3
3
|
pattern: string;
|
|
4
4
|
operationId: string;
|
|
5
5
|
}
|
|
6
|
-
export type OpenApiOperationId = "credits" | "creditsAlias" | "askAnonymous" | "askKeyed" | "search" | "searchKeyed" | "verify" | "verifyKeyed" | "research" | "researchKeyed" | "mcp" | "datasets" | "keyUsage" | "health" | "listConversations" | "createConversation" | "getConversation" | "renameConversation" | "deleteConversation" | "appendMessage" | "shareConversation" | "getShared" | "uploadAttachment" | "listAttachments" | "getAttachment" | "deleteAttachment" | "listMemories" | "createMemory" | "deleteMemory" | "listProjects" | "createProject" | "deleteProject" | "listProjectFiles" | "attachProjectFile" | "detachProjectFile" | "laneQuery" | "laneKeyed" | "feedback" | "adminEnrich" | "adminEnrichAlias" | "adminSection" | "adminFamilySummary" | "adminSectionAlias" | "adminFamilySummaryAlias" | "adminVectors" | "adminCaption" | "adminJudge" | "adminJudgeAlias" | "adminRevokeKey" | "authMe" | "authLogin" | "authCallback" | "authLogout" | "authLogoutLink" | "adminStats" | "adminListKeys" | "adminCreateKey";
|
|
6
|
+
export type OpenApiOperationId = "credits" | "creditsAlias" | "askAnonymous" | "askKeyed" | "search" | "searchKeyed" | "verify" | "verifyKeyed" | "research" | "researchKeyed" | "mcp" | "datasets" | "keyUsage" | "health" | "listConversations" | "createConversation" | "getConversation" | "renameConversation" | "deleteConversation" | "appendMessage" | "shareConversation" | "getShared" | "uploadAttachment" | "listAttachments" | "getAttachment" | "deleteAttachment" | "listMemories" | "createMemory" | "deleteMemory" | "listProjects" | "createProject" | "deleteProject" | "listProjectFiles" | "attachProjectFile" | "detachProjectFile" | "laneQuery" | "laneKeyed" | "feedback" | "adminEnrich" | "adminEnrichAlias" | "adminSection" | "adminFamilySummary" | "adminSectionAlias" | "adminFamilySummaryAlias" | "adminVectors" | "adminCaption" | "adminVisionJudge" | "adminJudge" | "adminJudgeAlias" | "adminRevokeKey" | "authMe" | "authLogin" | "authCallback" | "authLogout" | "authLogoutLink" | "adminStats" | "adminListKeys" | "adminCreateKey";
|
|
7
7
|
export declare const OPENAPI_SURFACE: readonly (Omit<OpenApiRoute, "operationId"> & {
|
|
8
8
|
operationId: OpenApiOperationId;
|
|
9
9
|
})[];
|
package/dist/openapi-types.d.ts
CHANGED
|
@@ -753,6 +753,26 @@ export interface paths {
|
|
|
753
753
|
patch?: never;
|
|
754
754
|
trace?: never;
|
|
755
755
|
};
|
|
756
|
+
"/admin/vision_judge": {
|
|
757
|
+
parameters: {
|
|
758
|
+
query?: never;
|
|
759
|
+
header?: never;
|
|
760
|
+
path?: never;
|
|
761
|
+
cookie?: never;
|
|
762
|
+
};
|
|
763
|
+
get?: never;
|
|
764
|
+
put?: never;
|
|
765
|
+
/**
|
|
766
|
+
* Judge two captions of one figure against the image
|
|
767
|
+
* @description The caption A/B's pairwise judge — two anonymized descriptions of the same figure, presented in randomized order beside the image itself, decided by a third model that took no part in writing either. The vision A/B harness calls this lane.
|
|
768
|
+
*/
|
|
769
|
+
post: operations["adminVisionJudge"];
|
|
770
|
+
delete?: never;
|
|
771
|
+
options?: never;
|
|
772
|
+
head?: never;
|
|
773
|
+
patch?: never;
|
|
774
|
+
trace?: never;
|
|
775
|
+
};
|
|
756
776
|
"/v1/admin/judge": {
|
|
757
777
|
parameters: {
|
|
758
778
|
query?: never;
|
|
@@ -2164,11 +2184,44 @@ export interface operations {
|
|
|
2164
2184
|
unit_id: string;
|
|
2165
2185
|
/** @description Surrounding clause text, at most 400 characters, to steer the description. */
|
|
2166
2186
|
context?: string;
|
|
2187
|
+
/** @description Per-request vision model override (an @cf/ id) — the caption A/B's measurement arm. Absent, the CAPTION_MODEL role (default glm-5.3-flash) serves. */
|
|
2188
|
+
model?: string;
|
|
2189
|
+
/** @description Return the description without storing it into the unit's payload. */
|
|
2190
|
+
dry_run?: boolean;
|
|
2191
|
+
};
|
|
2192
|
+
};
|
|
2193
|
+
};
|
|
2194
|
+
responses: {
|
|
2195
|
+
/** @description The description (stored, or returned only under dry_run). */
|
|
2196
|
+
200: {
|
|
2197
|
+
headers: {
|
|
2198
|
+
[name: string]: unknown;
|
|
2199
|
+
};
|
|
2200
|
+
content?: never;
|
|
2201
|
+
};
|
|
2202
|
+
};
|
|
2203
|
+
};
|
|
2204
|
+
adminVisionJudge: {
|
|
2205
|
+
parameters: {
|
|
2206
|
+
query?: never;
|
|
2207
|
+
header?: never;
|
|
2208
|
+
path?: never;
|
|
2209
|
+
cookie?: never;
|
|
2210
|
+
};
|
|
2211
|
+
requestBody: {
|
|
2212
|
+
content: {
|
|
2213
|
+
"application/json": {
|
|
2214
|
+
/** @description The figure unit whose asset the captions describe. */
|
|
2215
|
+
unit_id: string;
|
|
2216
|
+
captions: {
|
|
2217
|
+
a: string;
|
|
2218
|
+
b: string;
|
|
2219
|
+
};
|
|
2167
2220
|
};
|
|
2168
2221
|
};
|
|
2169
2222
|
};
|
|
2170
2223
|
responses: {
|
|
2171
|
-
/** @description The
|
|
2224
|
+
/** @description The winning arm (a or b) with the judge's reason. */
|
|
2172
2225
|
200: {
|
|
2173
2226
|
headers: {
|
|
2174
2227
|
[name: string]: unknown;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
handleSearch
|
|
3
|
+
} from "./chunk-MUWO2EV6.js";
|
|
4
|
+
import "./chunk-CLDMP5YH.js";
|
|
5
|
+
import "./chunk-ZHT4456M.js";
|
|
6
|
+
import "./chunk-D7MO4RVQ.js";
|
|
7
|
+
import "./chunk-ETLSWSZ7.js";
|
|
8
|
+
import "./chunk-FNQ7UOEB.js";
|
|
9
|
+
import "./chunk-HWWJAJWM.js";
|
|
10
|
+
import "./chunk-3FYJM7LH.js";
|
|
11
|
+
import "./chunk-KINFFYQH.js";
|
|
12
|
+
export {
|
|
13
|
+
handleSearch
|
|
14
|
+
};
|
|
@@ -4,10 +4,10 @@ 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-B2MU4ZWM.js";
|
|
8
|
+
import "./chunk-ZHT4456M.js";
|
|
9
|
+
import "./chunk-FNQ7UOEB.js";
|
|
10
|
+
import "./chunk-HWWJAJWM.js";
|
|
11
11
|
import "./chunk-3FYJM7LH.js";
|
|
12
12
|
import "./chunk-KINFFYQH.js";
|
|
13
13
|
export {
|
|
@@ -4,16 +4,16 @@ import {
|
|
|
4
4
|
handleMemories,
|
|
5
5
|
scoreFaithfulness,
|
|
6
6
|
scoreJudge
|
|
7
|
-
} from "../../chunk-
|
|
7
|
+
} from "../../chunk-ZZLUGHZ2.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-B2MU4ZWM.js";
|
|
14
14
|
import {
|
|
15
15
|
handleSearch
|
|
16
|
-
} from "../../chunk-
|
|
16
|
+
} from "../../chunk-MUWO2EV6.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-CLDMP5YH.js";
|
|
42
42
|
import {
|
|
43
43
|
embed,
|
|
44
44
|
generateOnce
|
|
45
|
-
} from "../../chunk-
|
|
45
|
+
} from "../../chunk-ZHT4456M.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-D7MO4RVQ.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-FNQ7UOEB.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-HWWJAJWM.js";
|
|
73
73
|
import {
|
|
74
74
|
P,
|
|
75
75
|
setProfile
|
|
@@ -581,6 +581,70 @@ ${chain || "(no successor edges recorded)"}` }
|
|
|
581
581
|
return err(502, "family_summary_failed", String(e?.message ?? e).slice(0, 200));
|
|
582
582
|
}
|
|
583
583
|
}
|
|
584
|
+
async function loadUnitAsset(env, unitId) {
|
|
585
|
+
const row = await env.DB.prepare("SELECT payload, docidentifier FROM unit_payloads WHERE unit_id = ?1").bind(unitId).first();
|
|
586
|
+
if (!row) return { error: err(404, "not_found", "no unit_payload row for that id") };
|
|
587
|
+
const payload = JSON.parse(String(row.payload));
|
|
588
|
+
const uri = payload.uri ?? "";
|
|
589
|
+
const m = uri.match(/^\/assets\/(.+)/);
|
|
590
|
+
if (!m) return { error: err(400, "invalid_input", "payload has no /assets/ uri (upload the asset first)") };
|
|
591
|
+
const obj = await env.UNIT_ASSETS.get(m[1]);
|
|
592
|
+
if (!obj) return { error: err(404, "not_found", `asset ${m[1]} not in R2`) };
|
|
593
|
+
const buf = await obj.arrayBuffer();
|
|
594
|
+
const ext = m[1].split(".").pop()?.toLowerCase() ?? "png";
|
|
595
|
+
const mime = ext === "svg" ? "image/svg+xml" : `image/${ext === "jpg" ? "jpeg" : ext}`;
|
|
596
|
+
const bytes = new Uint8Array(buf);
|
|
597
|
+
let binary = "";
|
|
598
|
+
for (let i = 0; i < bytes.length; i += 8192) binary += String.fromCharCode(...bytes.subarray(i, i + 8192));
|
|
599
|
+
return { row, b64: btoa(binary), mime };
|
|
600
|
+
}
|
|
601
|
+
async function handleVisionJudge(env, req) {
|
|
602
|
+
if (!env.ADMIN_TOKEN) return err(501, "admin_disabled", "ADMIN_TOKEN secret is not configured");
|
|
603
|
+
const auth = req.headers.get("authorization") ?? "";
|
|
604
|
+
if (auth !== `Bearer ${env.ADMIN_TOKEN}`) return err(401, "unauthorized", "Invalid admin token");
|
|
605
|
+
const body = await readJson(req);
|
|
606
|
+
const unitId = typeof body?.unit_id === "string" ? body.unit_id : "";
|
|
607
|
+
const capA = typeof body?.captions?.a === "string" ? body.captions.a.slice(0, 2e3) : "";
|
|
608
|
+
const capB = typeof body?.captions?.b === "string" ? body.captions.b.slice(0, 2e3) : "";
|
|
609
|
+
if (!unitId || !capA || !capB) return err(400, "invalid_input", "unit_id and captions.a/.b required");
|
|
610
|
+
try {
|
|
611
|
+
const loaded = await loadUnitAsset(env, unitId);
|
|
612
|
+
if (loaded.error) return loaded.error;
|
|
613
|
+
const swap = Math.random() < 0.5;
|
|
614
|
+
const first = swap ? capB : capA;
|
|
615
|
+
const second = swap ? capA : capB;
|
|
616
|
+
const res = await env.AI.run(roleModel(env, "visionJudge"), {
|
|
617
|
+
messages: [
|
|
618
|
+
{
|
|
619
|
+
role: "user",
|
|
620
|
+
content: [
|
|
621
|
+
{ type: "text", text: `You are judging two descriptions of the same figure (from ${loaded.row.docidentifier}) written for a reader who cannot see it. The figure is attached.
|
|
622
|
+
|
|
623
|
+
Description 1: ${first}
|
|
624
|
+
|
|
625
|
+
Description 2: ${second}
|
|
626
|
+
|
|
627
|
+
Which description better tells the reader what the figure shows and its normative point? Reply with ONLY JSON: {"better": 1 or 2, "reason": "one sentence"}.` },
|
|
628
|
+
{ type: "image_url", image_url: { url: `data:${loaded.mime};base64,${loaded.b64}` } }
|
|
629
|
+
]
|
|
630
|
+
}
|
|
631
|
+
],
|
|
632
|
+
// the DeepSeek law: reasoning is always on — a 2048 budget starved
|
|
633
|
+
// the verdict to empty content (the E.2.2.x judges failed on
|
|
634
|
+
// "Unexpected end of JSON input"); 4096 leaves the JSON intact
|
|
635
|
+
max_tokens: 4096
|
|
636
|
+
});
|
|
637
|
+
const anyRes = res;
|
|
638
|
+
const text = typeof anyRes?.response === "string" ? anyRes.response : anyRes?.choices?.[0]?.message?.content ?? "";
|
|
639
|
+
const parsed = JSON.parse(text.replace(/^[^\{]*/, "").replace(/[^\}]*$/, ""));
|
|
640
|
+
const said = parsed?.better === 1 ? "first" : parsed?.better === 2 ? "second" : null;
|
|
641
|
+
if (!said) return err(502, "judge_failed", "no decision in the judge's reply: " + text.slice(0, 120));
|
|
642
|
+
const winner = said === "first" === swap ? "b" : "a";
|
|
643
|
+
return json({ ok: true, unit_id: unitId, better: winner, judge: roleModel(env, "visionJudge"), reason: String(parsed.reason ?? "").slice(0, 500) });
|
|
644
|
+
} catch (e) {
|
|
645
|
+
return err(502, "vision_judge_failed", String(e).slice(0, 200));
|
|
646
|
+
}
|
|
647
|
+
}
|
|
584
648
|
async function handleCaption(env, req) {
|
|
585
649
|
if (!env.ADMIN_TOKEN) return err(501, "admin_disabled", "ADMIN_TOKEN secret is not configured");
|
|
586
650
|
const auth = req.headers.get("authorization") ?? "";
|
|
@@ -588,27 +652,19 @@ async function handleCaption(env, req) {
|
|
|
588
652
|
const body = await readJson(req);
|
|
589
653
|
const unitId = typeof body?.unit_id === "string" ? body.unit_id : "";
|
|
590
654
|
const context = typeof body?.context === "string" ? body.context.slice(0, 400) : "";
|
|
655
|
+
const override = typeof body?.model === "string" && body.model.startsWith("@cf/") ? body.model : null;
|
|
656
|
+
const dryRun = body?.dry_run === true;
|
|
591
657
|
if (!unitId) return err(400, "invalid_input", "unit_id required");
|
|
592
658
|
try {
|
|
593
|
-
const
|
|
594
|
-
if (
|
|
595
|
-
const
|
|
596
|
-
const
|
|
597
|
-
const
|
|
598
|
-
if (!m) return err(400, "invalid_input", "payload has no /assets/ uri (upload the asset first)");
|
|
599
|
-
const obj = await env.UNIT_ASSETS.get(m[1]);
|
|
600
|
-
if (!obj) return err(404, "not_found", `asset ${m[1]} not in R2`);
|
|
601
|
-
const buf = await obj.arrayBuffer();
|
|
602
|
-
const ext = m[1].split(".").pop()?.toLowerCase() ?? "png";
|
|
603
|
-
const mime = ext === "svg" ? "image/svg+xml" : `image/${ext === "jpg" ? "jpeg" : ext}`;
|
|
604
|
-
const bytes = new Uint8Array(buf);
|
|
605
|
-
let binary = "";
|
|
606
|
-
for (let i = 0; i < bytes.length; i += 8192) binary += String.fromCharCode(...bytes.subarray(i, i + 8192));
|
|
607
|
-
const b64 = btoa(binary);
|
|
659
|
+
const loaded = await loadUnitAsset(env, unitId);
|
|
660
|
+
if (loaded.error) return loaded.error;
|
|
661
|
+
const row = loaded.row;
|
|
662
|
+
const b64 = loaded.b64;
|
|
663
|
+
const mime = loaded.mime;
|
|
608
664
|
let res = null;
|
|
609
665
|
for (let attempt = 0; attempt < 2 && !res; attempt++) {
|
|
610
666
|
try {
|
|
611
|
-
res = await env.AI.run(
|
|
667
|
+
res = await env.AI.run(override ?? roleModel(env, "caption"), {
|
|
612
668
|
messages: [
|
|
613
669
|
{
|
|
614
670
|
role: "user",
|
|
@@ -636,8 +692,8 @@ async function handleCaption(env, req) {
|
|
|
636
692
|
const end = Math.max(cut.lastIndexOf(". "), cut.lastIndexOf("! "), cut.lastIndexOf("? "));
|
|
637
693
|
return end === -1 ? cut.slice(0, cut.lastIndexOf(" ")) : cut.slice(0, end + 1);
|
|
638
694
|
})();
|
|
639
|
-
await env.DB.prepare("UPDATE unit_payloads SET payload = json_set(payload, '$.description', ?1) WHERE unit_id = ?2").bind(desc, unitId).run();
|
|
640
|
-
return json({ ok: true, unit_id: unitId, description: desc });
|
|
695
|
+
if (!dryRun) await env.DB.prepare("UPDATE unit_payloads SET payload = json_set(payload, '$.description', ?1) WHERE unit_id = ?2").bind(desc, unitId).run();
|
|
696
|
+
return json({ ok: true, unit_id: unitId, model: override ?? roleModel(env, "caption"), dry_run: dryRun || void 0, description: desc });
|
|
641
697
|
} catch (e) {
|
|
642
698
|
return err(502, "caption_failed", String(e).slice(0, 200));
|
|
643
699
|
}
|
|
@@ -1119,13 +1175,13 @@ async function callToolOnce(env, ctx, _req, tier, key, name, args, t0) {
|
|
|
1119
1175
|
// stream:false forces the JSON lane (anon defaults to SSE)
|
|
1120
1176
|
body: JSON.stringify({ ...args, stream: false })
|
|
1121
1177
|
});
|
|
1122
|
-
const { runTool, TOOLS_REGISTRY: TOOLS_REGISTRY2 } = await import("../../tools-
|
|
1178
|
+
const { runTool, TOOLS_REGISTRY: TOOLS_REGISTRY2 } = await import("../../tools-VHN54DWH.js");
|
|
1123
1179
|
let payload;
|
|
1124
1180
|
if (TOOLS_REGISTRY2.some((t) => t.name === name && t.audiences.includes("mcp"))) {
|
|
1125
1181
|
const r = await runTool({ ...env, DB: env.DB }, { name, args }, "mcp");
|
|
1126
1182
|
payload = r ? { tool: r.name, query: r.query, result: r.output } : { error: { message: `tool ${name} returned nothing for the given arguments` } };
|
|
1127
1183
|
} else {
|
|
1128
|
-
const res = name === "ask" ? await (await import("../../ask-
|
|
1184
|
+
const res = name === "ask" ? await (await import("../../ask-7TNQCRD6.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-KNPPTHMG.js")).handleSearch(env, ctx, inner, tier, key);
|
|
1129
1185
|
payload = await res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
|
|
1130
1186
|
}
|
|
1131
1187
|
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 });
|
|
@@ -1392,6 +1448,11 @@ var OPENAPI_SURFACE = [
|
|
|
1392
1448
|
"pattern": "/admin/caption",
|
|
1393
1449
|
"operationId": "adminCaption"
|
|
1394
1450
|
},
|
|
1451
|
+
{
|
|
1452
|
+
"method": "POST",
|
|
1453
|
+
"pattern": "/admin/vision_judge",
|
|
1454
|
+
"operationId": "adminVisionJudge"
|
|
1455
|
+
},
|
|
1395
1456
|
{
|
|
1396
1457
|
"method": "POST",
|
|
1397
1458
|
"pattern": "/v1/admin/judge",
|
|
@@ -1933,6 +1994,7 @@ var OPENAPI_HANDLERS = {
|
|
|
1933
1994
|
adminSectionAlias: (c) => handleSectionUnit(c.env, c.ctx, c.req),
|
|
1934
1995
|
adminVectors: (c) => handleVectors(c.env, c.req),
|
|
1935
1996
|
adminCaption: (c) => handleCaption(c.env, c.req),
|
|
1997
|
+
adminVisionJudge: (c) => handleVisionJudge(c.env, c.req),
|
|
1936
1998
|
adminJudge: (c) => handleJudge(c.env, c.req),
|
|
1937
1999
|
adminJudgeAlias: (c) => handleJudge(c.env, c.req)
|
|
1938
2000
|
};
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
requestSalt,
|
|
5
5
|
resolveRequestScope,
|
|
6
6
|
standardKeysFrom
|
|
7
|
-
} from "../../chunk-
|
|
8
|
-
import "../../chunk-
|
|
7
|
+
} from "../../chunk-FNQ7UOEB.js";
|
|
8
|
+
import "../../chunk-HWWJAJWM.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.175",
|
|
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",
|
|
@@ -1007,9 +1007,47 @@ paths:
|
|
|
1007
1007
|
context:
|
|
1008
1008
|
type: string
|
|
1009
1009
|
description: Surrounding clause text, at most 400 characters, to steer the description.
|
|
1010
|
+
model:
|
|
1011
|
+
type: string
|
|
1012
|
+
description: >-
|
|
1013
|
+
Per-request vision model override (an @cf/ id) — the
|
|
1014
|
+
caption A/B's measurement arm. Absent, the CAPTION_MODEL
|
|
1015
|
+
role (default glm-5.3-flash) serves.
|
|
1016
|
+
dry_run:
|
|
1017
|
+
type: boolean
|
|
1018
|
+
description: Return the description without storing it into the unit's payload.
|
|
1019
|
+
responses:
|
|
1020
|
+
'200':
|
|
1021
|
+
description: The description (stored, or returned only under dry_run).
|
|
1022
|
+
/admin/vision_judge:
|
|
1023
|
+
post:
|
|
1024
|
+
tags: [Administration]
|
|
1025
|
+
summary: Judge two captions of one figure against the image
|
|
1026
|
+
description: >-
|
|
1027
|
+
The caption A/B's pairwise judge — two anonymized descriptions of
|
|
1028
|
+
the same figure, presented in randomized order beside the image
|
|
1029
|
+
itself, decided by a third model that took no part in writing
|
|
1030
|
+
either. The vision A/B harness calls this lane.
|
|
1031
|
+
operationId: adminVisionJudge
|
|
1032
|
+
security: [{ adminAuth: [] }]
|
|
1033
|
+
requestBody:
|
|
1034
|
+
required: true
|
|
1035
|
+
content:
|
|
1036
|
+
application/json:
|
|
1037
|
+
schema:
|
|
1038
|
+
type: object
|
|
1039
|
+
required: [unit_id, captions]
|
|
1040
|
+
properties:
|
|
1041
|
+
unit_id: { type: string, description: The figure unit whose asset the captions describe. }
|
|
1042
|
+
captions:
|
|
1043
|
+
type: object
|
|
1044
|
+
required: [a, b]
|
|
1045
|
+
properties:
|
|
1046
|
+
a: { type: string }
|
|
1047
|
+
b: { type: string }
|
|
1010
1048
|
responses:
|
|
1011
1049
|
'200':
|
|
1012
|
-
description: The
|
|
1050
|
+
description: The winning arm (a or b) with the judge's reason.
|
|
1013
1051
|
/v1/admin/judge:
|
|
1014
1052
|
post:
|
|
1015
1053
|
tags: [Administration]
|
|
@@ -264,6 +264,77 @@ export async function handleFamilySummary(env: Env, req: Request): Promise<Respo
|
|
|
264
264
|
/** Ops access to the Vectorize binding (get/upsert by id) for offline
|
|
265
265
|
* passes like embedding smoothing (G-ETSI-4) — the binding is the
|
|
266
266
|
* credential, admin-token gated exactly like /admin/enrich. */
|
|
267
|
+
/** The unit's vision asset, base64-encoded for the message part — the
|
|
268
|
+
* one load path the caption and the pairwise judge share. */
|
|
269
|
+
async function loadUnitAsset(env: Env, unitId: string) {
|
|
270
|
+
const row = await env.DB.prepare("SELECT payload, docidentifier FROM unit_payloads WHERE unit_id = ?1").bind(unitId).first<any>();
|
|
271
|
+
if (!row) return { error: err(404, "not_found", "no unit_payload row for that id") };
|
|
272
|
+
const payload = JSON.parse(String(row.payload));
|
|
273
|
+
const uri = payload.uri ?? "";
|
|
274
|
+
const m = uri.match(/^\/assets\/(.+)/);
|
|
275
|
+
if (!m) return { error: err(400, "invalid_input", "payload has no /assets/ uri (upload the asset first)") };
|
|
276
|
+
const obj = await env.UNIT_ASSETS.get(m[1]);
|
|
277
|
+
if (!obj) return { error: err(404, "not_found", `asset ${m[1]} not in R2`) };
|
|
278
|
+
const buf = await obj.arrayBuffer();
|
|
279
|
+
const ext = m[1].split(".").pop()?.toLowerCase() ?? "png";
|
|
280
|
+
const mime = ext === "svg" ? "image/svg+xml" : `image/${ext === "jpg" ? "jpeg" : ext}`;
|
|
281
|
+
// chunked: spreading the whole byte array blows the V8 stack on large
|
|
282
|
+
// assets (the 389KB u:figure-1)
|
|
283
|
+
const bytes = new Uint8Array(buf);
|
|
284
|
+
let binary = "";
|
|
285
|
+
for (let i = 0; i < bytes.length; i += 8192) binary += String.fromCharCode(...bytes.subarray(i, i + 8192));
|
|
286
|
+
return { row, b64: btoa(binary), mime };
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** The pairwise vision judge (TODO.sota/18.4's A/B): two anonymized
|
|
290
|
+
* captions of the SAME figure, presented in randomized order beside the
|
|
291
|
+
* image itself; a THIRD model (never a contestant) picks the better
|
|
292
|
+
* caption with a reason. Admin-gated; one-time quality-first lane. */
|
|
293
|
+
export async function handleVisionJudge(env: Env, req: Request): Promise<Response> {
|
|
294
|
+
if (!env.ADMIN_TOKEN) return err(501, "admin_disabled", "ADMIN_TOKEN secret is not configured");
|
|
295
|
+
const auth = req.headers.get("authorization") ?? "";
|
|
296
|
+
if (auth !== `Bearer ${env.ADMIN_TOKEN}`) return err(401, "unauthorized", "Invalid admin token");
|
|
297
|
+
const body = await readJson(req);
|
|
298
|
+
const unitId = typeof body?.unit_id === "string" ? body.unit_id : "";
|
|
299
|
+
const capA = typeof body?.captions?.a === "string" ? body.captions.a.slice(0, 2000) : "";
|
|
300
|
+
const capB = typeof body?.captions?.b === "string" ? body.captions.b.slice(0, 2000) : "";
|
|
301
|
+
if (!unitId || !capA || !capB) return err(400, "invalid_input", "unit_id and captions.a/.b required");
|
|
302
|
+
try {
|
|
303
|
+
const loaded = await loadUnitAsset(env, unitId);
|
|
304
|
+
if (loaded.error) return loaded.error;
|
|
305
|
+
// randomized presentation order: the judge's letter bias must not
|
|
306
|
+
// correlate with either arm
|
|
307
|
+
const swap = Math.random() < 0.5;
|
|
308
|
+
const first = swap ? capB : capA;
|
|
309
|
+
const second = swap ? capA : capB;
|
|
310
|
+
const res = await env.AI.run(roleModel(env, "visionJudge"), {
|
|
311
|
+
messages: [
|
|
312
|
+
{
|
|
313
|
+
role: "user",
|
|
314
|
+
content: [
|
|
315
|
+
{ type: "text", text: `You are judging two descriptions of the same figure (from ${loaded.row.docidentifier}) written for a reader who cannot see it. The figure is attached.\n\nDescription 1: ${first}\n\nDescription 2: ${second}\n\nWhich description better tells the reader what the figure shows and its normative point? Reply with ONLY JSON: {"better": 1 or 2, "reason": "one sentence"}.` },
|
|
316
|
+
{ type: "image_url", image_url: { url: `data:${loaded.mime};base64,${loaded.b64}` } },
|
|
317
|
+
],
|
|
318
|
+
},
|
|
319
|
+
],
|
|
320
|
+
// the DeepSeek law: reasoning is always on — a 2048 budget starved
|
|
321
|
+
// the verdict to empty content (the E.2.2.x judges failed on
|
|
322
|
+
// "Unexpected end of JSON input"); 4096 leaves the JSON intact
|
|
323
|
+
max_tokens: 4096,
|
|
324
|
+
});
|
|
325
|
+
const anyRes = res as any;
|
|
326
|
+
const text = typeof anyRes?.response === "string" ? anyRes.response : anyRes?.choices?.[0]?.message?.content ?? "";
|
|
327
|
+
const parsed = JSON.parse(text.replace(/^[^\{]*/, "").replace(/[^\}]*$/, ""));
|
|
328
|
+
const said = parsed?.better === 1 ? "first" : parsed?.better === 2 ? "second" : null;
|
|
329
|
+
if (!said) return err(502, "judge_failed", "no decision in the judge's reply: " + text.slice(0, 120));
|
|
330
|
+
// map back through the presentation swap
|
|
331
|
+
const winner = (said === "first") === swap ? "b" : "a";
|
|
332
|
+
return json({ ok: true, unit_id: unitId, better: winner, judge: roleModel(env, "visionJudge"), reason: String(parsed.reason ?? "").slice(0, 500) });
|
|
333
|
+
} catch (e) {
|
|
334
|
+
return err(502, "vision_judge_failed", String(e).slice(0, 200));
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
267
338
|
/** One-time figure captioning (TODO.remaining/03): fetch the unit's asset
|
|
268
339
|
* from R2, describe it with the vision-capable answer model, store the
|
|
269
340
|
* description into unit_payloads. Admin-gated; idempotent. */
|
|
@@ -274,29 +345,22 @@ export async function handleCaption(env: Env, req: Request): Promise<Response> {
|
|
|
274
345
|
const body = await readJson(req);
|
|
275
346
|
const unitId = typeof body?.unit_id === "string" ? body.unit_id : "";
|
|
276
347
|
const context = typeof body?.context === "string" ? body.context.slice(0, 400) : "";
|
|
348
|
+
// the A/B arm (TODO.sota/18.4): a per-request model override for the
|
|
349
|
+
// measurement, admin-gated like the route itself; dry_run skips the
|
|
350
|
+
// payload write so the arms never mix state in unit_payloads
|
|
351
|
+
const override = typeof body?.model === "string" && body.model.startsWith("@cf/") ? body.model : null;
|
|
352
|
+
const dryRun = body?.dry_run === true;
|
|
277
353
|
if (!unitId) return err(400, "invalid_input", "unit_id required");
|
|
278
354
|
try {
|
|
279
|
-
const
|
|
280
|
-
if (
|
|
281
|
-
const
|
|
282
|
-
const
|
|
283
|
-
const
|
|
284
|
-
if (!m) return err(400, "invalid_input", "payload has no /assets/ uri (upload the asset first)");
|
|
285
|
-
const obj = await env.UNIT_ASSETS.get(m[1]);
|
|
286
|
-
if (!obj) return err(404, "not_found", `asset ${m[1]} not in R2`);
|
|
287
|
-
const buf = await obj.arrayBuffer();
|
|
288
|
-
const ext = m[1].split(".").pop()?.toLowerCase() ?? "png";
|
|
289
|
-
const mime = ext === "svg" ? "image/svg+xml" : `image/${ext === "jpg" ? "jpeg" : ext}`;
|
|
290
|
-
// chunked: spreading the whole byte array blows the V8 stack on large
|
|
291
|
-
// assets (the 389KB u:figure-1)
|
|
292
|
-
const bytes = new Uint8Array(buf);
|
|
293
|
-
let binary = "";
|
|
294
|
-
for (let i = 0; i < bytes.length; i += 8192) binary += String.fromCharCode(...bytes.subarray(i, i + 8192));
|
|
295
|
-
const b64 = btoa(binary);
|
|
355
|
+
const loaded = await loadUnitAsset(env, unitId);
|
|
356
|
+
if (loaded.error) return loaded.error;
|
|
357
|
+
const row = loaded.row;
|
|
358
|
+
const b64 = loaded.b64;
|
|
359
|
+
const mime = loaded.mime;
|
|
296
360
|
let res: any = null;
|
|
297
361
|
for (let attempt = 0; attempt < 2 && !res; attempt++) {
|
|
298
362
|
try {
|
|
299
|
-
res = await env.AI.run(
|
|
363
|
+
res = await env.AI.run(override ?? roleModel(env, "caption"), {
|
|
300
364
|
messages: [
|
|
301
365
|
{
|
|
302
366
|
role: "user",
|
|
@@ -331,8 +395,8 @@ export async function handleCaption(env: Env, req: Request): Promise<Response> {
|
|
|
331
395
|
const end = Math.max(cut.lastIndexOf(". "), cut.lastIndexOf("! "), cut.lastIndexOf("? "));
|
|
332
396
|
return end === -1 ? cut.slice(0, cut.lastIndexOf(" ")) : cut.slice(0, end + 1);
|
|
333
397
|
})();
|
|
334
|
-
await env.DB.prepare("UPDATE unit_payloads SET payload = json_set(payload, '$.description', ?1) WHERE unit_id = ?2").bind(desc, unitId).run();
|
|
335
|
-
return json({ ok: true, unit_id: unitId, description: desc });
|
|
398
|
+
if (!dryRun) await env.DB.prepare("UPDATE unit_payloads SET payload = json_set(payload, '$.description', ?1) WHERE unit_id = ?2").bind(desc, unitId).run();
|
|
399
|
+
return json({ ok: true, unit_id: unitId, model: override ?? roleModel(env, "caption"), dry_run: dryRun || undefined, description: desc });
|
|
336
400
|
} catch (e) {
|
|
337
401
|
return err(502, "caption_failed", String(e).slice(0, 200));
|
|
338
402
|
}
|
|
@@ -35,7 +35,7 @@ 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";
|
|
38
|
+
import { decisionsEnabled, gateQuestion, runDecisionPass, telemetryDecisions } from "./decisionWire";
|
|
39
39
|
import type { DecisionItem } from "./decisions";
|
|
40
40
|
import { STAGE_NAMES } from "./stages/index.ts";
|
|
41
41
|
import { routeFor, fastRouteStages } from "./route.ts";
|
|
@@ -1730,15 +1730,21 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1730
1730
|
let streamedCompletionBlocks: Awaited<ReturnType<typeof completeTables>> = [];
|
|
1731
1731
|
// the decision pass's section streams as the answer's tail
|
|
1732
1732
|
// (the pass ran concurrently with generation — its arrival is
|
|
1733
|
-
// instant here), before the completions and the done event
|
|
1734
|
-
|
|
1733
|
+
// instant here), before the completions and the done event.
|
|
1734
|
+
// Stand-down law (TODO.decisions/00): where a deterministic
|
|
1735
|
+
// engine (verdict, condition, aggregation) answered, its block
|
|
1736
|
+
// is authoritative — the checklist never rides beside it.
|
|
1737
|
+
let streamedDecisions: { mode: string; gate: number; items: DecisionItem[] } | undefined;
|
|
1738
|
+
if (decisionPromise && !canonical0.includes(refusalAnswer()) && !verdictBlock && !conditionBlock && !aggregationBlock) {
|
|
1735
1739
|
const dp = await decisionPromise;
|
|
1736
1740
|
if (dp) {
|
|
1737
1741
|
canonical0 += dp.section;
|
|
1738
1742
|
send({ type: "token", v: dp.section });
|
|
1739
1743
|
full += dp.section;
|
|
1744
|
+
streamedDecisions = { mode: dp.mode, gate: dp.gate, items: dp.items };
|
|
1740
1745
|
console.log("decisions: streamed the checklist section (" + dp.items.length + " items, mode " + dp.mode + ")");
|
|
1741
1746
|
}
|
|
1747
|
+
telemetryDecisions(env, ctx, tier, queryHash, streamedDecisions ?? null, Date.now() - tStart);
|
|
1742
1748
|
}
|
|
1743
1749
|
if (!canonical0.includes(refusalAnswer())) {
|
|
1744
1750
|
try {
|
|
@@ -1747,7 +1753,7 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1747
1753
|
if (streamedCompletionBlocks.length) console.log("streamed completion:", streamedCompletionBlocks.length, "block(s) attached");
|
|
1748
1754
|
} catch { /* additive — the answer stands without the blocks */ }
|
|
1749
1755
|
}
|
|
1750
|
-
send({ type: "done", model, query_hash: queryHash, follow_ups: refusalShaped(canonical0, refusalScope(answerCites(full))) ? [] : (understanding?.follow_ups ?? []), blocks: [...c2.blocks, ...(verdictBlock ? [verdictBlock] : []), ...(conditionBlock ? [conditionBlock] : []), ...(aggregationBlock ? [aggregationBlock] : []), ...streamedCompletionBlocks], context_applied: ctxApplied, read: readAs(),
|
|
1756
|
+
send({ type: "done", model, query_hash: queryHash, follow_ups: refusalShaped(canonical0, refusalScope(answerCites(full))) ? [] : (understanding?.follow_ups ?? []), ...(streamedDecisions ? { decisions: streamedDecisions } : {}), blocks: [...c2.blocks, ...(verdictBlock ? [verdictBlock] : []), ...(conditionBlock ? [conditionBlock] : []), ...(aggregationBlock ? [aggregationBlock] : []), ...streamedCompletionBlocks], context_applied: ctxApplied, read: readAs(),
|
|
1751
1757
|
// the evidence view's ground truth: the exact passages this
|
|
1752
1758
|
// answer was built from, compact — cache hits carry none,
|
|
1753
1759
|
// because the cache stores the answer and never the passages
|
|
@@ -2083,10 +2089,11 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
2083
2089
|
let decisionsOut: { mode: string; gate: number; items: DecisionItem[] } | undefined;
|
|
2084
2090
|
if (decisionPromise) {
|
|
2085
2091
|
const dp = await decisionPromise;
|
|
2086
|
-
if (dp && answer && !answer!.includes(refusalAnswer())) {
|
|
2092
|
+
if (dp && answer && !answer!.includes(refusalAnswer()) && !verdictBlock && !conditionBlock && !aggregationBlock) {
|
|
2087
2093
|
answer = answer! + dp.section;
|
|
2088
2094
|
decisionsOut = { mode: dp.mode, gate: dp.gate, items: dp.items };
|
|
2089
2095
|
}
|
|
2096
|
+
telemetryDecisions(env, ctx, tier, queryHash, decisionsOut ?? null, Date.now() - tStart);
|
|
2090
2097
|
}
|
|
2091
2098
|
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 } };
|
|
2092
2099
|
const cacheable = !contextual && !declaredCtx && !ablate && cacheableAnswer(answer!, refusalScope(answerCites(answer!))) && finalAnchors.violations.length === 0;
|
|
@@ -7,6 +7,13 @@ export const MODELS = {
|
|
|
7
7
|
// Vision image-parts land with answer contract v2; text answers work now.
|
|
8
8
|
anon: "@cf/zai-org/glm-5.3-flash",
|
|
9
9
|
member: "@cf/zai-org/glm-5.3-flash",
|
|
10
|
+
// figure captions + the vision lane (one-time, quality-first; the A/B
|
|
11
|
+
// lever is CAPTION_MODEL, the per-request arm is the admin route's
|
|
12
|
+
// body.model)
|
|
13
|
+
caption: "@cf/zai-org/glm-5.3-flash",
|
|
14
|
+
// the pairwise vision judge (sees the image; a THIRD model never
|
|
15
|
+
// judges its own arm)
|
|
16
|
+
visionJudge: "@cf/deepseek-ai/deepseek-v4.1-flash-1017",
|
|
10
17
|
// the VLM figure rerank (TODO.sota/18.3): the newly-landed
|
|
11
18
|
// vision-capable MoE scores figure IMAGES against figure-seeking
|
|
12
19
|
// questions — one bounded call per figure question, ablatable stage
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// when DECISIONS_ENABLED, not ablated, not a refusal, no verdict block
|
|
5
5
|
// bound, and the gate's noul clears decisionsGateMin.
|
|
6
6
|
import { portModelRunner } from "./env.ts";
|
|
7
|
+
import { telemetry } from "./quota";
|
|
7
8
|
import { MODELS, THRESHOLDS } from "./config.ts";
|
|
8
9
|
import {
|
|
9
10
|
buildDecisionQuestions, matchAnswers, parseDerivation,
|
|
@@ -91,7 +92,11 @@ export async function runDecisionPass(
|
|
|
91
92
|
`Each requirement's clause = the clause anchor it comes from. If nothing qualifies, return {"mode":"list","requirements":[]}.`,
|
|
92
93
|
},
|
|
93
94
|
],
|
|
94
|
-
maxTokens:
|
|
95
|
+
maxTokens: 3072,
|
|
96
|
+
// the GLM law: the effort defaults to MAX when absent — an omitted
|
|
97
|
+
// effort starved the derivation to empty (observed live: the pass
|
|
98
|
+
// stood down silently on every fired question)
|
|
99
|
+
effort: "low",
|
|
95
100
|
temperature: 0,
|
|
96
101
|
});
|
|
97
102
|
const { mode, requirements } = parseDerivation(derived.text, THRESHOLDS.decisionsRequirementsMax);
|
|
@@ -122,3 +127,27 @@ export async function runDecisionPass(
|
|
|
122
127
|
return null; // additive — the essay answer ships
|
|
123
128
|
}
|
|
124
129
|
}
|
|
130
|
+
|
|
131
|
+
/** The decisions telemetry (TODO.decisions/03): the nightly's
|
|
132
|
+
* calibration signal, riding the queries table's route key with a
|
|
133
|
+
* defined encoding — no schema migration.
|
|
134
|
+
* - one PASS row, route "ask-decisions": ok = fired, lang = mode,
|
|
135
|
+
* model = the gate probability (2dp), duration_ms = the pass's.
|
|
136
|
+
* - one ITEM row per requirement, route "ask-decision": ok = band is
|
|
137
|
+
* "met", lang = band, model = the probability (2dp); query_hash
|
|
138
|
+
* joins the rows to their pass. */
|
|
139
|
+
export function telemetryDecisions(
|
|
140
|
+
env: Env,
|
|
141
|
+
ctx: { waitUntil(p: Promise<unknown>): void },
|
|
142
|
+
tier: string,
|
|
143
|
+
queryHash: string,
|
|
144
|
+
result: { mode: string; gate: number; items: DecisionItem[] } | null,
|
|
145
|
+
durationMs: number,
|
|
146
|
+
): void {
|
|
147
|
+
try {
|
|
148
|
+
telemetry(env, ctx, tier, "ask-decisions", result ? result.gate.toFixed(2) : "0", !!result, result?.items.length ?? 0, queryHash, result?.mode ?? undefined, undefined, { durationMs });
|
|
149
|
+
for (const it of result?.items ?? []) {
|
|
150
|
+
telemetry(env, ctx, tier, "ask-decision", it.probability.toFixed(2), it.band === "met", 1, queryHash, it.band, undefined, {});
|
|
151
|
+
}
|
|
152
|
+
} catch { /* telemetry never answers for the answer */ }
|
|
153
|
+
}
|
|
@@ -23,7 +23,7 @@ import { json, err, corsHeaders, withCors, readJson, authenticate, type ApiKey }
|
|
|
23
23
|
import { creditBudget, clientIp } from "./quota";
|
|
24
24
|
|
|
25
25
|
import { handleSearch } from "./search";
|
|
26
|
-
import { handleEnrich, handleSectionUnit, handleCaption, handleVectors, handleJudge, handleCreateKey, handleListKeys, handleRevokeKey, handleKeyUsage, handleFamilySummary } from "./admin";
|
|
26
|
+
import { handleEnrich, handleSectionUnit, handleCaption, handleVisionJudge, handleVectors, handleJudge, handleCreateKey, handleListKeys, handleRevokeKey, handleKeyUsage, handleFamilySummary } from "./admin";
|
|
27
27
|
import { handleResearch } from "./research";
|
|
28
28
|
import { uploadAttachment, readAttachment, deleteAttachment, type AttachmentDeps } from "./attachments";
|
|
29
29
|
import { cfBlobs } from "./ports/cloudflare/adapters";
|
|
@@ -639,6 +639,7 @@ const OPENAPI_HANDLERS: Record<OpenApiOperationId, RouteHandler> = {
|
|
|
639
639
|
adminSectionAlias: (c) => handleSectionUnit(c.env, c.ctx, c.req),
|
|
640
640
|
adminVectors: (c) => handleVectors(c.env, c.req),
|
|
641
641
|
adminCaption: (c) => handleCaption(c.env, c.req),
|
|
642
|
+
adminVisionJudge: (c) => handleVisionJudge(c.env, c.req),
|
|
642
643
|
adminJudge: (c) => handleJudge(c.env, c.req),
|
|
643
644
|
adminJudgeAlias: (c) => handleJudge(c.env, c.req),
|
|
644
645
|
};
|
|
@@ -53,6 +53,7 @@ export type OpenApiOperationId =
|
|
|
53
53
|
| "adminFamilySummaryAlias"
|
|
54
54
|
| "adminVectors"
|
|
55
55
|
| "adminCaption"
|
|
56
|
+
| "adminVisionJudge"
|
|
56
57
|
| "adminJudge"
|
|
57
58
|
| "adminJudgeAlias"
|
|
58
59
|
| "adminRevokeKey"
|
|
@@ -296,6 +297,11 @@ export const OPENAPI_SURFACE: readonly (Omit<OpenApiRoute, "operationId"> & { op
|
|
|
296
297
|
"pattern": "/admin/caption",
|
|
297
298
|
"operationId": "adminCaption"
|
|
298
299
|
},
|
|
300
|
+
{
|
|
301
|
+
"method": "POST",
|
|
302
|
+
"pattern": "/admin/vision_judge",
|
|
303
|
+
"operationId": "adminVisionJudge"
|
|
304
|
+
},
|
|
299
305
|
{
|
|
300
306
|
"method": "POST",
|
|
301
307
|
"pattern": "/v1/admin/judge",
|
package/dist/ask-BKWQEMSY.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
handleAsk
|
|
3
|
-
} from "./chunk-PO3UBDNZ.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
|
-
};
|
package/dist/search-RNCRT5BR.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
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
|
-
};
|