@konneal/engine 0.2.86 → 0.2.87

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-PIEUN5B2.js";
3
+ } from "./chunk-PQCRL5TL.js";
4
4
  import "./chunk-GCK6DW7E.js";
5
5
  import "./chunk-7HWJOFTQ.js";
6
6
  import "./chunk-SPKPH54J.js";
@@ -2871,6 +2871,26 @@ ${q.query}`.replace("\n\n\n\n", "\n\n") }];
2871
2871
  }
2872
2872
  const tq2 = await chargeAnswerTokens(env, bucketId, stats, messageChars(messages), full.length);
2873
2873
  send({ type: "quota", quota: { ...quota, ...tq2 } });
2874
+ if (withImage && register?.rows?.length && full.includes(refusalAnswer())) {
2875
+ console.log("blind-answer(stream): regenerating once");
2876
+ mark("Re-answering from the register results");
2877
+ send({ type: "retry" });
2878
+ const regen = await generateStream(env, model, [
2879
+ ...messages.slice(0, -1),
2880
+ { role: "user", content: "The photograph was attached and the register note lists actual matching certificate rows. Present those rows \u2014 number, holder, model, status, and every document link \u2014 as the answer. Do not claim that nothing was provided." },
2881
+ messages[messages.length - 1]
2882
+ ], effort);
2883
+ if (regen) {
2884
+ full = "";
2885
+ try {
2886
+ for await (const tok of sseTokens(regen)) {
2887
+ full += tok;
2888
+ send({ type: "token", v: tok });
2889
+ }
2890
+ } catch {
2891
+ }
2892
+ }
2893
+ }
2874
2894
  const canonical0 = canonicalRefusal(full);
2875
2895
  const c2 = canonical0.includes(refusalAnswer()) ? { text: canonical0, blocks: [], dropped: [] } : await contractV2(env.DB, canonical0, usedHits);
2876
2896
  send({
@@ -6,7 +6,7 @@ import {
6
6
  modelGroundingBlock,
7
7
  scoreFaithfulness,
8
8
  scoreJudge
9
- } from "../../chunk-PIEUN5B2.js";
9
+ } from "../../chunk-PQCRL5TL.js";
10
10
  import {
11
11
  TOOLS_REGISTRY
12
12
  } from "../../chunk-GCK6DW7E.js";
@@ -976,7 +976,7 @@ async function handleMcp(env, ctx, req, tier, key) {
976
976
  const r = await runTool({ ...env, DB: env.DB }, { name, args });
977
977
  return r ? { tool: r.name, query: r.query, result: r.output } : { error: { message: `tool ${name} returned nothing for the given arguments` } };
978
978
  }
979
- const res = name === "ask" ? await (await import("../../ask-XM5FO6LR.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-LVUQLA3C.js")).handleSearch(env, ctx, inner, tier, key);
979
+ const res = name === "ask" ? await (await import("../../ask-IDMQUJBY.js")).handleAsk(env, ctx, inner, tier, key) : await (await import("../../search-LVUQLA3C.js")).handleSearch(env, ctx, inner, tier, key);
980
980
  return res.json().catch(() => ({ error: { message: "tool transport failed", status: res.status } }));
981
981
  });
982
982
  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.86",
30
+ "version": "0.2.87",
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",
@@ -1329,6 +1329,32 @@ let convEntities: Array<{ entity: string; kind: string }> = [];
1329
1329
  }
1330
1330
  const tq = await chargeAnswerTokens(env, bucketId, stats, messageChars(messages), full.length);
1331
1331
  send({ type: "quota", quota: { ...quota, ...tq } });
1332
+ // the blind-answer guard ON THE STREAM PATH (the JSON path has
1333
+ // had it since 0.2.80): an image rode the turn, the register
1334
+ // note carries rows, and the streamed text is the no-information
1335
+ // refusal — the multimodal call answered around the photograph.
1336
+ // One bounded regeneration: the retry sentinel tells the client
1337
+ // to clear the buffer, the agent step says why, and the fresh
1338
+ // tokens stream as the answer.
1339
+ if (withImage && register?.rows?.length && full.includes(refusalAnswer())) {
1340
+ console.log("blind-answer(stream): regenerating once");
1341
+ mark("Re-answering from the register results");
1342
+ send({ type: "retry" });
1343
+ const regen = await generateStream(env, model, [
1344
+ ...messages.slice(0, -1),
1345
+ { role: "user", content: "The photograph was attached and the register note lists actual matching certificate rows. Present those rows — number, holder, model, status, and every document link — as the answer. Do not claim that nothing was provided." },
1346
+ messages[messages.length - 1],
1347
+ ], effort);
1348
+ if (regen) {
1349
+ full = "";
1350
+ try {
1351
+ for await (const tok of sseTokens(regen)) {
1352
+ full += tok;
1353
+ send({ type: "token", v: tok });
1354
+ }
1355
+ } catch { /* deliver what we have */ }
1356
+ }
1357
+ }
1332
1358
  const canonical0 = canonicalRefusal(full);
1333
1359
  // answer contract v2: validate [[u:]] refs, resolve typed blocks
1334
1360
  const c2 = canonical0.includes(refusalAnswer())