@konneal/engine 0.2.40 → 0.2.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  handleAsk
3
- } from "./chunk-5SLSRFOG.js";
3
+ } from "./chunk-JG5GRJCZ.js";
4
4
  import "./chunk-N2UOENDY.js";
5
5
  import "./chunk-R2V3X6SQ.js";
6
6
  import "./chunk-A3QHHUN5.js";
@@ -2449,8 +2449,9 @@ Answer account questions from these records ONLY: name the record when you use i
2449
2449
  );
2450
2450
  await attachFigureImages(env, messages, usedHits, q.query);
2451
2451
  if (userImage) {
2452
+ const wantsMarkings = /\b(mark(ing|ings)?|nameplate|label|inscription|engrav|sticker|plate)\b|certificat/i.test(q.query);
2452
2453
  const last = messages[messages.length - 1];
2453
- const note = "\n\n(The user attached an image with this question; interpret it directly when answering.)";
2454
+ 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.)";
2454
2455
  if (Array.isArray(last.content)) {
2455
2456
  const textPart = last.content.find((p) => p.type === "text");
2456
2457
  if (textPart) textPart.text += note;
@@ -2476,7 +2477,7 @@ Answer account questions from these records ONLY: name the record when you use i
2476
2477
  `));
2477
2478
  send({ type: "read", read: readAs() });
2478
2479
  const sourceQuality = answerQuality(cites.map((c) => c.quality));
2479
- send({ type: "citations", citations: cites, context_applied: ctxApplied, ...sourceQuality ? { source_quality: sourceQuality, quality_note: qualityNote(sourceQuality), ...sourceQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(cites) } : {} } : {}, ...liveRecords ? { records: liveRecords } : {}, quota });
2480
+ send({ type: "citations", citations: cites, context_applied: ctxApplied, ...sourceQuality ? { source_quality: sourceQuality, confidence_note: qualityNote(sourceQuality), ...sourceQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(cites) } : {} } : {}, ...liveRecords ? { records: liveRecords } : {}, quota });
2480
2481
  let full = "";
2481
2482
  try {
2482
2483
  for await (const tok of sseTokens(stream)) {
@@ -2610,7 +2611,7 @@ Answer account questions from these records ONLY: name the record when you use i
2610
2611
  }
2611
2612
  completionBlocks.push(...await completeFigures(env.DB, answer, [...c2ns.blocks, ...completionBlocks], used));
2612
2613
  const jsonQuality = answerQuality(finalCites.map((c) => c.quality));
2613
- const out = { answer, citations: finalCites, ...jsonQuality ? { source_quality: jsonQuality, quality_note: qualityNote(jsonQuality), ...jsonQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(finalCites) } : {} } : {}, model: MODELS.member, query_hash: queryHash, follow_ups: understanding?.follow_ups ?? [], blocks: [...c2ns.blocks, ...verdictBlock ? [verdictBlock] : [], ...conditionBlock ? [conditionBlock] : [], ...aggregationBlock ? [aggregationBlock] : [], ...completionBlocks], context_applied: ctxApplied, ...liveRecords ? { records: liveRecords } : {} };
2614
+ const out = { answer, citations: finalCites, ...jsonQuality ? { source_quality: jsonQuality, confidence_note: qualityNote(jsonQuality), ...jsonQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(finalCites) } : {} } : {}, model: MODELS.member, query_hash: queryHash, follow_ups: understanding?.follow_ups ?? [], blocks: [...c2ns.blocks, ...verdictBlock ? [verdictBlock] : [], ...conditionBlock ? [conditionBlock] : [], ...aggregationBlock ? [aggregationBlock] : [], ...completionBlocks], context_applied: ctxApplied, ...liveRecords ? { records: liveRecords } : {} };
2614
2615
  const cacheable = !contextual && !declaredCtx && !answer.includes(refusalAnswer()) && finalAnchors.violations.length === 0;
2615
2616
  if (cacheable) {
2616
2617
  const warmVec = await warmEmbed ?? null;
@@ -9,7 +9,7 @@ import {
9
9
  modelGroundingBlock,
10
10
  scoreJudge,
11
11
  standardForDocNumber
12
- } from "../../chunk-5SLSRFOG.js";
12
+ } from "../../chunk-JG5GRJCZ.js";
13
13
  import {
14
14
  buildMessages,
15
15
  citations,
@@ -999,7 +999,7 @@ async function handleMcp(env, ctx, req, tier, key) {
999
999
  // stream:false forces the JSON lane (anon defaults to SSE)
1000
1000
  body: JSON.stringify({ ...args, stream: false })
1001
1001
  });
1002
- const res = name === "ask" ? await (await import("../../ask-QHODBUU2.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-QZDQVB57.js")).handleSearch(env, ctx, inner, tier, key);
1002
+ const res = name === "ask" ? await (await import("../../ask-3LIAXR4S.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-QZDQVB57.js")).handleSearch(env, ctx, inner, tier, key);
1003
1003
  return res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
1004
1004
  });
1005
1005
  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.40",
30
+ "version": "0.2.41",
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",
@@ -1115,9 +1115,16 @@ async function handleAsk(
1115
1115
  await attachFigureImages(env, messages, usedHits, q.query);
1116
1116
  if (userImage) {
1117
1117
  // the user's own image rides on the question message — retrieval stays
1118
- // text-driven; the answer model reads the image as question context
1118
+ // text-driven; the answer model reads the image as question context.
1119
+ // A markings/nameplate/certificate photo gets a TRANSCRIPTION note:
1120
+ // read the inscriptions verbatim first, then interpret from the
1121
+ // passages (the marking requirements are corpus content) — never
1122
+ // invent a marking that cannot be read.
1123
+ const wantsMarkings = /\b(mark(ing|ings)?|nameplate|label|inscription|engrav|sticker|plate)\b|certificat/i.test(q.query);
1119
1124
  const last = messages[messages.length - 1];
1120
- const note = "\n\n(The user attached an image with this question; interpret it directly when answering.)";
1125
+ const note = wantsMarkings
1126
+ ? "\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.)"
1127
+ : "\n\n(The user attached an image with this question; interpret it directly when answering.)";
1121
1128
  if (Array.isArray(last.content)) {
1122
1129
  const textPart = last.content.find((p: any) => p.type === "text");
1123
1130
  if (textPart) textPart.text += note;
@@ -1147,7 +1154,7 @@ async function handleAsk(
1147
1154
  // retrieval, before a single token of the answer
1148
1155
  send({ type: "read", read: readAs() });
1149
1156
  const sourceQuality = answerQuality(cites.map((c: any) => c.quality));
1150
- send({ type: "citations", citations: cites, context_applied: ctxApplied, ...(sourceQuality ? { source_quality: sourceQuality, quality_note: qualityNote(sourceQuality), ...(sourceQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(cites) } : {}) } : {}), ...(liveRecords ? { records: liveRecords } : {}), quota, });
1157
+ send({ type: "citations", citations: cites, context_applied: ctxApplied, ...(sourceQuality ? { source_quality: sourceQuality, confidence_note: qualityNote(sourceQuality), ...(sourceQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(cites) } : {}) } : {}), ...(liveRecords ? { records: liveRecords } : {}), quota, });
1151
1158
  let full = "";
1152
1159
  try {
1153
1160
  for await (const tok of sseTokens(stream)) {
@@ -1342,7 +1349,7 @@ async function handleAsk(
1342
1349
  completionBlocks.push(...(await completeFigures(env.DB, answer, [...c2ns.blocks, ...completionBlocks], used)));
1343
1350
 
1344
1351
  const jsonQuality = answerQuality(finalCites.map((c: any) => c.quality));
1345
- const out = { answer, citations: finalCites, ...(jsonQuality ? { source_quality: jsonQuality, quality_note: qualityNote(jsonQuality), ...(jsonQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(finalCites) } : {}) } : {}), model: MODELS.member, query_hash: queryHash, follow_ups: understanding?.follow_ups ?? [], blocks: [...c2ns.blocks, ...(verdictBlock ? [verdictBlock] : []), ...(conditionBlock ? [conditionBlock] : []), ...(aggregationBlock ? [aggregationBlock] : []), ...completionBlocks], context_applied: ctxApplied, ...(liveRecords ? { records: liveRecords } : {}) };
1352
+ const out = { answer, citations: finalCites, ...(jsonQuality ? { source_quality: jsonQuality, confidence_note: qualityNote(jsonQuality), ...(jsonQuality === "ocr" ? { experimental_sources: experimentalSourceLabels(finalCites) } : {}) } : {}), model: MODELS.member, query_hash: queryHash, follow_ups: understanding?.follow_ups ?? [], blocks: [...c2ns.blocks, ...(verdictBlock ? [verdictBlock] : []), ...(conditionBlock ? [conditionBlock] : []), ...(aggregationBlock ? [aggregationBlock] : []), ...completionBlocks], context_applied: ctxApplied, ...(liveRecords ? { records: liveRecords } : {}) };
1346
1353
  const cacheable = !contextual && !declaredCtx && !answer.includes(refusalAnswer()) && finalAnchors.violations.length === 0;
1347
1354
  if (cacheable) {
1348
1355
  const warmVec = (await warmEmbed) ?? null;