@intentic/webq 1.359.2 → 1.361.0

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 +1 @@
1
- {"version":3,"file":"bm25.d.ts","sourceRoot":"","sources":["../../src/lib/bm25.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW,CAAC,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,QAAQ,SAAU,MAAM,KAAG,MAAM,EAKtB,CAAC;AAyBzB,eAAO,MAAM,QAAQ,GAAI,CAAC,UAAU,SAAS,CAAC,EAAE,UAAU,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,SAAS,MAAM,KAAG,WAAW,CAAC,CAAC,CAAC,EA8B7G,CAAC"}
1
+ {"version":3,"file":"bm25.d.ts","sourceRoot":"","sources":["../../src/lib/bm25.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW,CAAC,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,QAAQ,SAAU,MAAM,KAAG,MAAM,EAKtB,CAAC;AAyBzB,eAAO,MAAM,QAAQ,GAAI,CAAC,UAAU,SAAS,CAAC,EAAE,UAAU,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,SAAS,MAAM,KAAG,WAAW,CAAC,CAAC,CAAC,EAsC7G,CAAC"}
package/dist/lib/bm25.js CHANGED
@@ -22,29 +22,36 @@ export const bm25Rank = (blocks, textOf, query) => {
22
22
  if (queryTerms.length === 0 || blocks.length === 0) {
23
23
  return [];
24
24
  }
25
- const docs = blocks.map((block) => tokenize(textOf(block)));
26
- const avgLen = docs.reduce((sum, doc) => sum + doc.length, 0) / docs.length || 1;
25
+ const wanted = new Set(queryTerms);
27
26
  const docFrequency = new Map();
28
- for (const term of queryTerms) {
29
- docFrequency.set(term, docs.filter((doc) => doc.includes(term)).length);
30
- }
31
- const scored = blocks.map((block, index) => {
32
- const doc = docs[index] ?? [];
27
+ const docs = blocks.map((block) => {
28
+ const tokens = tokenize(textOf(block));
33
29
  const counts = new Map();
34
- for (const token of doc) {
35
- counts.set(token, (counts.get(token) ?? 0) + 1);
30
+ for (const token of tokens) {
31
+ if (wanted.has(token)) {
32
+ counts.set(token, (counts.get(token) ?? 0) + 1);
33
+ }
34
+ }
35
+ for (const term of counts.keys()) {
36
+ docFrequency.set(term, (docFrequency.get(term) ?? 0) + 1);
36
37
  }
38
+ return { block, length: tokens.length, counts };
39
+ });
40
+ const avgLen = docs.reduce((sum, doc) => sum + doc.length, 0) / docs.length || 1;
41
+ const weights = queryTerms.map((term) => {
42
+ const df = docFrequency.get(term) ?? 0;
43
+ return { term, idf: df === 0 ? 0 : Math.log((docs.length - df + 0.5) / (df + 0.5) + 1) };
44
+ });
45
+ const scored = docs.map((doc) => {
37
46
  let score = 0;
38
- for (const term of queryTerms) {
39
- const df = docFrequency.get(term) ?? 0;
40
- if (df === 0) {
47
+ for (const { term, idf } of weights) {
48
+ const tf = doc.counts.get(term) ?? 0;
49
+ if (tf === 0) {
41
50
  continue;
42
51
  }
43
- const idf = Math.log((docs.length - df + 0.5) / (df + 0.5) + 1);
44
- const tf = counts.get(term) ?? 0;
45
52
  score += idf * ((tf * (K1 + 1)) / (tf + K1 * (1 - B + B * (doc.length / avgLen))));
46
53
  }
47
- return { block, score };
54
+ return { block: doc.block, score };
48
55
  });
49
56
  return scored.filter((entry) => entry.score > 0).toSorted((a, b) => b.score - a.score);
50
57
  };
@@ -1 +1 @@
1
- {"version":3,"file":"bm25.js","sourceRoot":"","sources":["../../src/lib/bm25.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bm25.js","sourceRoot":"","sources":["../../src/lib/bm25.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentic/webq",
3
- "version": "1.359.2",
3
+ "version": "1.361.0",
4
4
  "description": "webq, agent-native web fetch CLI: any URL as clean budgeted markdown, and bounded same-site crawls, over one shared cache",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,24 +45,23 @@
45
45
  }
46
46
  },
47
47
  "dependencies": {
48
- "@intentic/agent-cli": "1.359.2",
49
- "@intentic/base": "1.359.2",
48
+ "@intentic/agent-cli": "1.361.0",
49
+ "@intentic/base": "1.361.0",
50
50
  "@stricli/core": "1.3.0",
51
51
  "parse5": "8.0.1",
52
- "playwright": "1.63.0",
53
- "tslib": "2.8.1"
52
+ "playwright": "1.64.1"
54
53
  },
55
54
  "devDependencies": {
56
55
  "@intentic/testing": "0.0.0",
57
56
  "@intentic/tsconfig": "0.0.0",
58
- "@types/bun": "1.4.2",
59
- "@types/node": "24.19.1",
60
- "@typescript/native-preview": "7.0.0-dev.20260707.2"
57
+ "@types/bun": "1.4.4",
58
+ "@types/node": "24.19.2",
59
+ "typescript": "7.0.2"
61
60
  },
62
61
  "scripts": {
63
- "build": "tsgo",
62
+ "build": "tsc",
64
63
  "typecheck": "bun check -p tsconfig.test.json",
65
- "watch": "tsgo --build --watch",
64
+ "watch": "tsc --build --watch",
66
65
  "test": "suites",
67
66
  "test:watch": "suites --watch"
68
67
  }
@@ -30,4 +30,20 @@ describe("bm25Rank", () => {
30
30
  expect(bm25Rank(blocks, (block) => block, "")).toEqual([]);
31
31
  expect(bm25Rank(blocks, (block) => block, "zebra")).toEqual([]);
32
32
  });
33
+
34
+ it("counts document frequency once per block and folds duplicate query terms", () => {
35
+ const docs = ["webhook webhook", "webhook other", ""];
36
+ const ranked = bm25Rank(docs, (block) => block, "webhooks webhook missing");
37
+ expect(ranked.map((entry) => entry.block)).toEqual(docs.slice(0, 2));
38
+ const idf = Math.log(1 + 1.5 / 2.5);
39
+ expect(ranked[0]?.score).toBeCloseTo((idf * 4.4) / (2 + 1.2 * (0.25 + 0.75 * 1.5)), 12);
40
+ expect(ranked[1]?.score).toBeCloseTo((idf * 2.2) / (1 + 1.2 * (0.25 + 0.75 * 1.5)), 12);
41
+ });
42
+
43
+ it("keeps document order when scores tie and handles blocks with no tokens", () => {
44
+ const docs = [{ text: "webhook retry" }, { text: "retry webhook" }, { text: "!" }];
45
+ expect(bm25Rank(docs, (block) => block.text, "webhook").map((entry) => entry.block)).toEqual(docs.slice(0, 2));
46
+ expect(bm25Rank(["", "!"], (block) => block, "webhook")).toEqual([]);
47
+ expect(bm25Rank([], (block: string) => block, "webhook")).toEqual([]);
48
+ });
33
49
  });
package/src/lib/bm25.ts CHANGED
@@ -42,29 +42,37 @@ export const bm25Rank = <T>(blocks: readonly T[], textOf: (block: T) => string,
42
42
  if (queryTerms.length === 0 || blocks.length === 0) {
43
43
  return [];
44
44
  }
45
- const docs = blocks.map((block) => tokenize(textOf(block)));
46
- const avgLen = docs.reduce((sum, doc) => sum + doc.length, 0) / docs.length || 1;
45
+ const wanted = new Set(queryTerms);
47
46
  const docFrequency = new Map<string, number>();
48
- for (const term of queryTerms) {
49
- docFrequency.set(term, docs.filter((doc) => doc.includes(term)).length);
50
- }
51
- const scored = blocks.map((block, index) => {
52
- const doc = docs[index] ?? [];
47
+ const docs = blocks.map((block) => {
48
+ const tokens = tokenize(textOf(block));
53
49
  const counts = new Map<string, number>();
54
- for (const token of doc) {
55
- counts.set(token, (counts.get(token) ?? 0) + 1);
50
+ for (const token of tokens) {
51
+ if (wanted.has(token)) {
52
+ counts.set(token, (counts.get(token) ?? 0) + 1);
53
+ }
54
+ }
55
+ // A repeated word still contributes only one document to its document frequency.
56
+ for (const term of counts.keys()) {
57
+ docFrequency.set(term, (docFrequency.get(term) ?? 0) + 1);
56
58
  }
59
+ return { block, length: tokens.length, counts };
60
+ });
61
+ const avgLen = docs.reduce((sum, doc) => sum + doc.length, 0) / docs.length || 1;
62
+ const weights = queryTerms.map((term) => {
63
+ const df = docFrequency.get(term) ?? 0;
64
+ return { term, idf: df === 0 ? 0 : Math.log((docs.length - df + 0.5) / (df + 0.5) + 1) };
65
+ });
66
+ const scored = docs.map((doc) => {
57
67
  let score = 0;
58
- for (const term of queryTerms) {
59
- const df = docFrequency.get(term) ?? 0;
60
- if (df === 0) {
68
+ for (const { term, idf } of weights) {
69
+ const tf = doc.counts.get(term) ?? 0;
70
+ if (tf === 0) {
61
71
  continue;
62
72
  }
63
- const idf = Math.log((docs.length - df + 0.5) / (df + 0.5) + 1);
64
- const tf = counts.get(term) ?? 0;
65
73
  score += idf * ((tf * (K1 + 1)) / (tf + K1 * (1 - B + B * (doc.length / avgLen))));
66
74
  }
67
- return { block, score };
75
+ return { block: doc.block, score };
68
76
  });
69
77
  return scored.filter((entry) => entry.score > 0).toSorted((a, b) => b.score - a.score);
70
78
  };