eddie-jekyll 0.4.0 → 0.4.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0fb05e7b2291be54f498bc2e2df6c8b75689e2fecd1e62f069b05712d78882f5
4
- data.tar.gz: 402f2f4a6569e9117f7acf584ff4d6966c05cf3601ce2909c3960b489d3180fd
3
+ metadata.gz: 8ee3de05bd384c3efa54ac0f02fe5ef965ad2ce916527ccfa64b8192e78f8a21
4
+ data.tar.gz: 74fce98d4bb02cf2b673ea7320e4d76945cba73174aa2d519f18af7a20e0a181
5
5
  SHA512:
6
- metadata.gz: 28c2cf42975d69ddaa552acb7ece03fe9a7f390d5eac410b35b49387c3f527f85c2b4a01e288f557b681b2a509e40b073deb6d174e5e6296547a0e9466683652
7
- data.tar.gz: a6159ac2597c2f1e294ef466d6d1e663cb0f753728e1fa97047a6992987891d5f998cf85d9b5752f61e27bdcf49ca40f7e28e53eb994b0313aece4f36e98aa17
6
+ metadata.gz: 57a741bc8deb39f770afb142fc6b627e2a716c621691e57aff0a3de5a0b3f097b3b93ca2994148ee8efbd5c0d5cd6233c95bbbc0c7ef8a3a4886021f1cbca49b
7
+ data.tar.gz: b50f5c323df27a301a03789542c53b5413e69e61a619b6a9945ce0d7fbb21cb1511eb9a9019c065973af2d38e37a705c8f1a598aa70ee54f25be05f3f3e94cfb
@@ -265,7 +265,36 @@ const EddieLib = {};
265
265
  return { answer: text, citations, nohit: text === "" };
266
266
  }
267
267
 
268
+
269
+ // FAQ card gate: prefer the WASM's fused `confident` flag (qa_lookup v0.4.1+);
270
+ // older indexes only carry a dense score, so fall back to a plain cutoff.
271
+ function faqPasses(hit, qaMode) {
272
+ if (!hit || typeof hit !== "object") return false;
273
+ if (qaMode === "off") return false;
274
+ if (qaMode === "always") return true;
275
+ if (typeof hit.confident === "boolean") return hit.confident;
276
+ return typeof hit.score === "number" && hit.score >= 0.5;
277
+ }
278
+
279
+ // Turn confident QA hits into agent evidence items ("Q: … A: …") so the
280
+ // answer model sees the FAQ lane, not only chunk text.
281
+ function qaEvidence(hits, max) {
282
+ const limit = max == null ? 2 : max;
283
+ const out = [];
284
+ for (const h of Array.isArray(hits) ? hits : []) {
285
+ if (out.length >= limit) break;
286
+ if (!faqPasses(h, "auto")) continue;
287
+ const q = String(h.question || "").trim();
288
+ const a = String(h.answer || "").trim();
289
+ if (!q || !a) continue;
290
+ out.push({ title: "FAQ: " + q, url: h.source_url || "", text: "Q: " + q + "\nA: " + a, faq: true });
291
+ }
292
+ return out;
293
+ }
294
+
268
295
  return {
296
+ faqPasses,
297
+ qaEvidence,
269
298
  NOHIT,
270
299
  AGENT_MODEL_SIZES,
271
300
  PLAN_SCHEMA,
data/assets/eddie-wasm.js CHANGED
@@ -181,8 +181,11 @@ let wasm_bindgen = (function(exports) {
181
181
  exports.page = page;
182
182
 
183
183
  /**
184
- * Nearest QA entries by cosine on the qa dense lane. Returns `[]` when the
185
- * index has no qa section or no query vector can be produced.
184
+ * QA entries ranked by [`crate::search::rank_qa`]: the qa dense lane's
185
+ * cosine fused with lexical overlap and a BM25 pass over the questions and
186
+ * answers. Returns `[]` when the index has no qa section; without a query
187
+ * vector (no runnable embedder) the ranking is lexical only and no hit is
188
+ * `confident`.
186
189
  * @param {string} query
187
190
  * @param {string | null | undefined} dense_lane_id
188
191
  * @param {Float32Array | null | undefined} dense_query_vec
@@ -639,7 +639,36 @@ const EddieLib = {};
639
639
  return { answer: text, citations, nohit: text === "" };
640
640
  }
641
641
 
642
+
643
+ // FAQ card gate: prefer the WASM's fused `confident` flag (qa_lookup v0.4.1+);
644
+ // older indexes only carry a dense score, so fall back to a plain cutoff.
645
+ function faqPasses(hit, qaMode) {
646
+ if (!hit || typeof hit !== "object") return false;
647
+ if (qaMode === "off") return false;
648
+ if (qaMode === "always") return true;
649
+ if (typeof hit.confident === "boolean") return hit.confident;
650
+ return typeof hit.score === "number" && hit.score >= 0.5;
651
+ }
652
+
653
+ // Turn confident QA hits into agent evidence items ("Q: … A: …") so the
654
+ // answer model sees the FAQ lane, not only chunk text.
655
+ function qaEvidence(hits, max) {
656
+ const limit = max == null ? 2 : max;
657
+ const out = [];
658
+ for (const h of Array.isArray(hits) ? hits : []) {
659
+ if (out.length >= limit) break;
660
+ if (!faqPasses(h, "auto")) continue;
661
+ const q = String(h.question || "").trim();
662
+ const a = String(h.answer || "").trim();
663
+ if (!q || !a) continue;
664
+ out.push({ title: "FAQ: " + q, url: h.source_url || "", text: "Q: " + q + "\nA: " + a, faq: true });
665
+ }
666
+ return out;
667
+ }
668
+
642
669
  return {
670
+ faqPasses,
671
+ qaEvidence,
643
672
  NOHIT,
644
673
  AGENT_MODEL_SIZES,
645
674
  PLAN_SCHEMA,
@@ -1659,8 +1688,7 @@ const EddieLib = {};
1659
1688
  return;
1660
1689
  }
1661
1690
  const best = hits[0];
1662
- const threshold = config.qaMode === "always" ? 0 : 0.5;
1663
- if (!best || typeof best.score !== "number" || best.score < threshold) {
1691
+ if (!lib.faqPasses(best, config.qaMode)) {
1664
1692
  hide(faqCard);
1665
1693
  return;
1666
1694
  }
@@ -1886,7 +1914,12 @@ const EddieLib = {};
1886
1914
  const evidence = lib.mergeEvidence(lists, 6);
1887
1915
  await expandShortEvidence(evidence);
1888
1916
  if (run.aborted) return;
1889
- run.evidence = evidence.map((r) => ({ title: r.title, url: r.url, text: r.text || r.snippet || "" }));
1917
+ // Confident FAQ entries (build-time QA lane) go first: they are short,
1918
+ // direct, and already carry a source page.
1919
+ const faqHits = await callWorker("qa", { query: question, k: 3 }).then((m) => m.hits || []).catch(() => []);
1920
+ if (run.aborted) return;
1921
+ const faqItems = lib.qaEvidence(faqHits, 2);
1922
+ run.evidence = faqItems.concat(evidence.map((r) => ({ title: r.title, url: r.url, text: r.text || r.snippet || "" })));
1890
1923
  answerProgress.textContent = "Answering…";
1891
1924
  await streamAnswer(run);
1892
1925
  } catch (err) {
data/assets/eddie.wasm CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eddie-jekyll
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Grey
@@ -18,7 +18,7 @@ dependencies:
18
18
  version: '0.4'
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 0.4.0
21
+ version: 0.4.1
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -28,7 +28,7 @@ dependencies:
28
28
  version: '0.4'
29
29
  - - ">="
30
30
  - !ruby/object:Gem::Version
31
- version: 0.4.0
31
+ version: 0.4.1
32
32
  description: Provides a CLI helper that runs Eddie's Jekyll installer script.
33
33
  executables:
34
34
  - eddie-jekyll-install