@konneal/engine 0.2.81 → 0.2.83
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/{ask-M2JPJFEM.js → ask-IAJDX2YY.js} +2 -2
- package/dist/{certificates-YFL4K7O3.js → certificates-CO7KX2S2.js} +1 -1
- package/dist/{chunk-7AQM3GSO.js → chunk-JZFXSTYX.js} +7 -2
- package/dist/{chunk-YWMM5XTC.js → chunk-TWK46PU2.js} +7 -10
- package/dist/pipeline.d.ts +1 -1
- package/dist/worker_public/src/index.js +3 -3
- package/package.json +1 -1
- package/workers/worker_public/src/ask.ts +12 -9
- package/workers/worker_public/src/certificates.ts +8 -1
- package/workers/worker_public/src/pipeline.ts +4 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handleAsk
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TWK46PU2.js";
|
|
4
4
|
import "./chunk-7HWJOFTQ.js";
|
|
5
5
|
import "./chunk-SPKPH54J.js";
|
|
6
6
|
import "./chunk-A3QHHUN5.js";
|
|
7
7
|
import "./chunk-LVZTWUVJ.js";
|
|
8
8
|
import "./chunk-2PCUAJJO.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-JZFXSTYX.js";
|
|
10
10
|
import "./chunk-3FYJM7LH.js";
|
|
11
11
|
export {
|
|
12
12
|
handleAsk
|
|
@@ -139,8 +139,13 @@ function registerNote(rows) {
|
|
|
139
139
|
}
|
|
140
140
|
function certificateLinks(rows) {
|
|
141
141
|
const links = rows.filter((r) => r.pdf_key).map((r) => `- ${r.num}: https://www.oimlsmart.org/cert-pdf/${r.pdf_key}`);
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
const absent = rows.filter((r) => !r.pdf_key && r.num).slice(0, 6).map((r) => `- ${r.num}: no document on file in this snapshot`);
|
|
143
|
+
const parts = [];
|
|
144
|
+
if (links.length) parts.push(`Documents on file:
|
|
145
|
+
${links.join("\n")}`);
|
|
146
|
+
if (absent.length) parts.push(`No document on file (do NOT construct a link for these):
|
|
147
|
+
${absent.join("\n")}`);
|
|
148
|
+
return parts.join("\n");
|
|
144
149
|
}
|
|
145
150
|
|
|
146
151
|
export {
|
|
@@ -72,7 +72,7 @@ import {
|
|
|
72
72
|
certificateLinks,
|
|
73
73
|
registerNote,
|
|
74
74
|
searchRegister
|
|
75
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-JZFXSTYX.js";
|
|
76
76
|
import {
|
|
77
77
|
P
|
|
78
78
|
} from "./chunk-3FYJM7LH.js";
|
|
@@ -1896,7 +1896,7 @@ async function runTool(db, call) {
|
|
|
1896
1896
|
if (call.name !== "register_search") return null;
|
|
1897
1897
|
const query = String(call.args?.query ?? "").trim().slice(0, 160);
|
|
1898
1898
|
if (!query) return null;
|
|
1899
|
-
const { searchRegister: searchRegister2, registerNote: registerNote2 } = await import("./certificates-
|
|
1899
|
+
const { searchRegister: searchRegister2, registerNote: registerNote2 } = await import("./certificates-CO7KX2S2.js");
|
|
1900
1900
|
const reg = await searchRegister2(db, query, true);
|
|
1901
1901
|
const output = reg?.rows?.length ? registerNote2(reg.rows) : `No certificate was found for "${query}" in the certificates database (the register snapshot). State this as the search's result, with the searched string visible.`;
|
|
1902
1902
|
return { name: call.name, query, output };
|
|
@@ -2880,7 +2880,7 @@ Answer account questions from these records ONLY: name the record when you use i
|
|
|
2880
2880
|
const imageTurn = typeof withImage === "string";
|
|
2881
2881
|
const probeMessages = [...messages.slice(0, -1), { role: "user", content: `${TOOL_DECLARATION}
|
|
2882
2882
|
|
|
2883
|
-
${imageTurn ? "A photograph of the instrument is attached after this message. Transcribe the maker, model and any printed certificate number you can read, then emit the TOOL line with those tokens as the query \u2014 never invented." : ""}
|
|
2883
|
+
${imageTurn ? "A photograph of the instrument is attached after this message. Transcribe the maker, model and any printed certificate number you can read FROM THE PHOTOGRAPH ITSELF, then emit the TOOL line with those tokens as the query \u2014 never invented, and never tokens taken from any register content elsewhere in the context (a register row's holder is not the plate's maker; observed live 2026-10-04)." : ""}
|
|
2884
2884
|
|
|
2885
2885
|
${q.query}`.replace("\n\n\n\n", "\n\n") }];
|
|
2886
2886
|
if (imageTurn) probeMessages.push({ role: "user", content: [{ type: "image_url", image_url: { url: withImage } }] });
|
|
@@ -2906,16 +2906,13 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
|
|
|
2906
2906
|
const wantsMarkings = /\b(mark(ing|ings)?|nameplate|label|inscription|engrav|sticker|plate)\b|certificat/i.test(q.query);
|
|
2907
2907
|
const last = messages[messages.length - 1];
|
|
2908
2908
|
const note = wantsMarkings ? "\n\n(The user attached a photo with this question. First transcribe every inscription you can actually read in the image \u2014 names, model references, accuracy classes, numeric values with their units, certificate or approval numbers \u2014 quoting them verbatim. Then answer the question from the numbered passages, citing the requirement each interpretation rests on. If an inscription is unreadable, say so; never invent a marking.)" : "\n\n(The user attached an image with this question; interpret it directly when answering.)";
|
|
2909
|
-
if (
|
|
2909
|
+
if (typeof last.content === "string") {
|
|
2910
|
+
last.content = last.content + note;
|
|
2911
|
+
} else {
|
|
2910
2912
|
const textPart = last.content.find((p) => p.type === "text");
|
|
2911
2913
|
if (textPart) textPart.text += note;
|
|
2912
|
-
last.content = [...last.content, { type: "image_url", image_url: { url: withImage } }];
|
|
2913
|
-
} else {
|
|
2914
|
-
last.content = [
|
|
2915
|
-
{ type: "text", text: last.content + note },
|
|
2916
|
-
{ type: "image_url", image_url: { url: withImage } }
|
|
2917
|
-
];
|
|
2918
2914
|
}
|
|
2915
|
+
messages.push({ role: "user", content: [{ type: "image_url", image_url: { url: withImage } }] });
|
|
2919
2916
|
console.log("user image attached to generation");
|
|
2920
2917
|
}
|
|
2921
2918
|
const queryHash = await sha256Hex(q.query);
|
package/dist/pipeline.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
modelGroundingBlock,
|
|
7
7
|
scoreFaithfulness,
|
|
8
8
|
scoreJudge
|
|
9
|
-
} from "../../chunk-
|
|
9
|
+
} from "../../chunk-TWK46PU2.js";
|
|
10
10
|
import {
|
|
11
11
|
handleSearch
|
|
12
12
|
} from "../../chunk-KO6DRI7C.js";
|
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
sha256Hex,
|
|
64
64
|
today
|
|
65
65
|
} from "../../chunk-2PCUAJJO.js";
|
|
66
|
-
import "../../chunk-
|
|
66
|
+
import "../../chunk-JZFXSTYX.js";
|
|
67
67
|
import {
|
|
68
68
|
P,
|
|
69
69
|
setProfile
|
|
@@ -959,7 +959,7 @@ async function handleMcp(env, ctx, req, tier, key) {
|
|
|
959
959
|
// stream:false forces the JSON lane (anon defaults to SSE)
|
|
960
960
|
body: JSON.stringify({ ...args, stream: false })
|
|
961
961
|
});
|
|
962
|
-
const res = name === "ask" ? await (await import("../../ask-
|
|
962
|
+
const res = name === "ask" ? await (await import("../../ask-IAJDX2YY.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-LVUQLA3C.js")).handleSearch(env, ctx, inner, tier, key);
|
|
963
963
|
return res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
|
|
964
964
|
});
|
|
965
965
|
if (out.ok && "accepted" in out) return new Response(null, { status: 202 });
|
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.83",
|
|
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",
|
|
@@ -85,7 +85,7 @@ function embedWarm(env: Env, text: string): Promise<number[] | null> {
|
|
|
85
85
|
* AI 8005s that scale with payload size), and only the ONE pinned
|
|
86
86
|
* figure attaches (the type-intent pin already chose the answering
|
|
87
87
|
* object; a second base64 blob doubles the flake surface for nothing). */
|
|
88
|
-
async function attachFigureImages(env: Env, messages: { role: string; content:
|
|
88
|
+
async function attachFigureImages(env: Env, messages: { role: string; content: any }[], usedHits: Hit[], query: string): Promise<void> {
|
|
89
89
|
// Attach only when the question WANTS the drawing (names a figure-ish
|
|
90
90
|
// artifact) or the pinned figure sits in the top prose passage's own
|
|
91
91
|
// clause (it IS the answering object) — a plain definition question
|
|
@@ -1230,7 +1230,7 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1230
1230
|
if (/certificate|certified|certification/i.test(q.query) && env.DB) {
|
|
1231
1231
|
try {
|
|
1232
1232
|
const imageTurn = typeof withImage === "string";
|
|
1233
|
-
const probeMessages: any[] = [...messages.slice(0, -1), { role: "user", content: `${TOOL_DECLARATION}\n\n${imageTurn ? "A photograph of the instrument is attached after this message. Transcribe the maker, model and any printed certificate number you can read, then emit the TOOL line with those tokens as the query — never invented." : ""}\n\n${q.query}`.replace("\n\n\n\n", "\n\n") }];
|
|
1233
|
+
const probeMessages: any[] = [...messages.slice(0, -1), { role: "user", content: `${TOOL_DECLARATION}\n\n${imageTurn ? "A photograph of the instrument is attached after this message. Transcribe the maker, model and any printed certificate number you can read FROM THE PHOTOGRAPH ITSELF, then emit the TOOL line with those tokens as the query — never invented, and never tokens taken from any register content elsewhere in the context (a register row's holder is not the plate's maker; observed live 2026-10-04)." : ""}\n\n${q.query}`.replace("\n\n\n\n", "\n\n") }];
|
|
1234
1234
|
if (imageTurn) probeMessages.push({ role: "user", content: [{ type: "image_url", image_url: { url: withImage } }] });
|
|
1235
1235
|
const probe = await (env as any).AI.run(model, {
|
|
1236
1236
|
messages: probeMessages,
|
|
@@ -1264,16 +1264,19 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
|
|
|
1264
1264
|
? "\n\n(The user attached a photo with this question. First transcribe every inscription you can actually read in the image — names, model references, accuracy classes, numeric values with their units, certificate or approval numbers — quoting them verbatim. Then answer the question from the numbered passages, citing the requirement each interpretation rests on. If an inscription is unreadable, say so; never invent a marking.)"
|
|
1265
1265
|
: "\n\n(The user attached an image with this question; interpret it directly when answering.)";
|
|
1266
1266
|
|
|
1267
|
-
|
|
1267
|
+
// the image rides its OWN SHORT TRAILING MESSAGE — never inside the
|
|
1268
|
+
// passage-bearing user message. Long text + image parts in ONE message
|
|
1269
|
+
// is the documented instability shape (2026-09-09); it was reintroduced
|
|
1270
|
+
// here, and the live "blindness" on photo answers (2026-10-03) was this
|
|
1271
|
+
// violation, not the model: the probe and extraction calls, which keep
|
|
1272
|
+
// the image on its own message, read the same plate every time.
|
|
1273
|
+
if (typeof last.content === "string") {
|
|
1274
|
+
last.content = last.content + note;
|
|
1275
|
+
} else {
|
|
1268
1276
|
const textPart = last.content.find((p: any) => p.type === "text");
|
|
1269
1277
|
if (textPart) textPart.text += note;
|
|
1270
|
-
last.content = [...last.content, { type: "image_url", image_url: { url: withImage } }] as unknown as string;
|
|
1271
|
-
} else {
|
|
1272
|
-
last.content = [
|
|
1273
|
-
{ type: "text", text: last.content + note },
|
|
1274
|
-
{ type: "image_url", image_url: { url: withImage } },
|
|
1275
|
-
] as unknown as string;
|
|
1276
1278
|
}
|
|
1279
|
+
messages.push({ role: "user", content: [{ type: "image_url", image_url: { url: withImage } }] });
|
|
1277
1280
|
console.log("user image attached to generation");
|
|
1278
1281
|
}
|
|
1279
1282
|
const queryHash = await sha256Hex(q.query);
|
|
@@ -163,6 +163,13 @@ export function registerNote(rows: RegisterRow[]): string {
|
|
|
163
163
|
* the fact. */
|
|
164
164
|
export function certificateLinks(rows: RegisterRow[]): string {
|
|
165
165
|
const links = rows.filter((r) => r.pdf_key).map((r) => `- ${r.num}: https://www.oimlsmart.org/cert-pdf/${r.pdf_key}`);
|
|
166
|
-
|
|
166
|
+
// absence is stated per row: an unmarked gap invited the model to
|
|
167
|
+
// generalize the URL pattern to a document-less row (a fabricated 404
|
|
168
|
+
// link, observed live 2026-10-04)
|
|
169
|
+
const absent = rows.filter((r) => !r.pdf_key && r.num).slice(0, 6).map((r) => `- ${r.num}: no document on file in this snapshot`);
|
|
170
|
+
const parts: string[] = [];
|
|
171
|
+
if (links.length) parts.push(`Documents on file:\n${links.join("\n")}`);
|
|
172
|
+
if (absent.length) parts.push(`No document on file (do NOT construct a link for these):\n${absent.join("\n")}`);
|
|
173
|
+
return parts.join("\n");
|
|
167
174
|
}
|
|
168
175
|
|
|
@@ -180,7 +180,10 @@ function clipToTokens(s: string, maxTok: number): string {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
export interface BuiltMessages {
|
|
183
|
-
|
|
183
|
+
// content is string OR an OpenAI-style parts array — the image parts
|
|
184
|
+
// ride their OWN trailing user message (never inside a passage-bearing
|
|
185
|
+
// one), so the type admits both shapes
|
|
186
|
+
messages: { role: string; content: string | any[] }[];
|
|
184
187
|
usedHits: Hit[]; // passages actually included (citations must match these)
|
|
185
188
|
}
|
|
186
189
|
|