bluera-knowledge 0.9.36 → 0.9.37
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/CHANGELOG.md +20 -0
- package/dist/{chunk-Z2KKVH45.js → chunk-6TKD5XE4.js} +2 -2
- package/dist/{chunk-DC7CGSGT.js → chunk-AT6G626F.js} +2 -2
- package/dist/{chunk-WFNPNAAP.js → chunk-CGDEV2RC.js} +59 -29
- package/dist/chunk-CGDEV2RC.js.map +1 -0
- package/dist/index.js +3 -3
- package/dist/mcp/server.js +2 -2
- package/dist/workers/background-worker-cli.js +2 -2
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/src/db/lance.ts +13 -19
- package/src/services/search.service.test.ts +209 -0
- package/src/services/search.service.ts +77 -19
- package/tests/integration/search-quality.test.ts +5 -3
- package/dist/chunk-WFNPNAAP.js.map +0 -1
- /package/dist/{chunk-Z2KKVH45.js.map → chunk-6TKD5XE4.js.map} +0 -0
- /package/dist/{chunk-DC7CGSGT.js.map → chunk-AT6G626F.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [0.9.37](https://github.com/blueraai/bluera-knowledge/compare/v0.9.32...v0.9.37) (2026-01-08)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **bridge:** kill Python process before nullifying to prevent zombie ([393dab3](https://github.com/blueraai/bluera-knowledge/commit/393dab3e45c75fd87c9ecfc1ca92e67b14526e79))
|
|
11
|
+
* **bridge:** mock kill() emits exit event & attach rejection handlers before stop ([d73c6ca](https://github.com/blueraai/bluera-knowledge/commit/d73c6ca6d640c3d15bd82756cabcda832f9ae245))
|
|
12
|
+
* **bridge:** stop() now waits for process to actually exit ([a92de41](https://github.com/blueraai/bluera-knowledge/commit/a92de41c89318fc106f996568ed88505352d5159))
|
|
13
|
+
* **cli:** ensure destroyServices runs before process.exit ([22e4267](https://github.com/blueraai/bluera-knowledge/commit/22e4267b7b9f698de3985a89b9c2b10759cfd49c))
|
|
14
|
+
* **code-unit:** brace counting now handles strings and comments ([1e857bb](https://github.com/blueraai/bluera-knowledge/commit/1e857bb297f357b97a6c067950e62495b3c8fc99))
|
|
15
|
+
* **code-unit:** support complex return types in signature extraction ([3bd2467](https://github.com/blueraai/bluera-knowledge/commit/3bd24675a67e73cc74a0c718f4b5a9e86cd826fb))
|
|
16
|
+
* **job:** validate PID before process.kill to prevent process group kill ([67c540f](https://github.com/blueraai/bluera-knowledge/commit/67c540fef6f2c55c5dca2c824104a91fe19aeff1))
|
|
17
|
+
* **search:** apply threshold filtering after score normalization ([1ebc78e](https://github.com/blueraai/bluera-knowledge/commit/1ebc78e0e688ffde0fdbaf049f17a35d129ef055))
|
|
18
|
+
* **services:** fail fast on corrupted config/registry files ([030f63c](https://github.com/blueraai/bluera-knowledge/commit/030f63c10b0a30bddcd8e9b27b291ab0f53263f1))
|
|
19
|
+
* **tests:** increase timeout for exit code test in CI ([a362dcd](https://github.com/blueraai/bluera-knowledge/commit/a362dcdae32b0c19e757270e5009b0c1c5ead4e4))
|
|
20
|
+
* **tests:** increase timeout for flaky store delete test ([738fb49](https://github.com/blueraai/bluera-knowledge/commit/738fb4975653703d800dee802730dedfdf9e85ba))
|
|
21
|
+
* **watch:** clear pending timeouts on unwatch to prevent timer leak ([4dcafc1](https://github.com/blueraai/bluera-knowledge/commit/4dcafc14417442f6eeed0257cf185e04ae9de12b))
|
|
22
|
+
* **worker:** fail fast on PID file write error ([d92ce42](https://github.com/blueraai/bluera-knowledge/commit/d92ce42eff63cee3c97056ef019f5a52ef699edd))
|
|
23
|
+
* **worker:** prevent division by zero and improve cancellation handling ([b7b40ab](https://github.com/blueraai/bluera-knowledge/commit/b7b40ab950b7ad0fbbe84af243be3138b1072a72))
|
|
24
|
+
|
|
5
25
|
## [0.9.36](https://github.com/blueraai/bluera-knowledge/compare/v0.9.32...v0.9.36) (2026-01-08)
|
|
6
26
|
|
|
7
27
|
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
createServices,
|
|
5
5
|
createStoreId,
|
|
6
6
|
summarizePayload
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-CGDEV2RC.js";
|
|
8
8
|
|
|
9
9
|
// src/mcp/server.ts
|
|
10
10
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -1086,4 +1086,4 @@ export {
|
|
|
1086
1086
|
createMCPServer,
|
|
1087
1087
|
runMCPServer
|
|
1088
1088
|
};
|
|
1089
|
-
//# sourceMappingURL=chunk-
|
|
1089
|
+
//# sourceMappingURL=chunk-6TKD5XE4.js.map
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
createLogger,
|
|
4
4
|
summarizePayload,
|
|
5
5
|
truncateForLog
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-CGDEV2RC.js";
|
|
7
7
|
|
|
8
8
|
// src/crawl/intelligent-crawler.ts
|
|
9
9
|
import { EventEmitter } from "events";
|
|
@@ -765,4 +765,4 @@ var IntelligentCrawler = class extends EventEmitter {
|
|
|
765
765
|
export {
|
|
766
766
|
IntelligentCrawler
|
|
767
767
|
};
|
|
768
|
-
//# sourceMappingURL=chunk-
|
|
768
|
+
//# sourceMappingURL=chunk-AT6G626F.js.map
|
|
@@ -2839,6 +2839,33 @@ var SearchService = class {
|
|
|
2839
2839
|
const lowerContent = content.toLowerCase();
|
|
2840
2840
|
return queryTerms.filter((term) => lowerContent.includes(term)).length;
|
|
2841
2841
|
}
|
|
2842
|
+
/**
|
|
2843
|
+
* Normalize scores to 0-1 range and optionally filter by threshold.
|
|
2844
|
+
* This ensures threshold values match displayed scores (UX consistency).
|
|
2845
|
+
*
|
|
2846
|
+
* Edge case handling:
|
|
2847
|
+
* - If there's only 1 result or all results have the same score, normalization
|
|
2848
|
+
* would make them all 1.0. In this case, we keep the raw scores to allow
|
|
2849
|
+
* threshold filtering to work meaningfully on absolute quality.
|
|
2850
|
+
*/
|
|
2851
|
+
normalizeAndFilterScores(results, threshold) {
|
|
2852
|
+
if (results.length === 0) return [];
|
|
2853
|
+
const sorted = [...results].sort((a, b) => b.score - a.score);
|
|
2854
|
+
const first = sorted[0];
|
|
2855
|
+
const last = sorted[sorted.length - 1];
|
|
2856
|
+
if (first === void 0 || last === void 0) return [];
|
|
2857
|
+
const maxScore = first.score;
|
|
2858
|
+
const minScore = last.score;
|
|
2859
|
+
const range = maxScore - minScore;
|
|
2860
|
+
const normalized = range > 0 ? sorted.map((r) => ({
|
|
2861
|
+
...r,
|
|
2862
|
+
score: Math.round((r.score - minScore) / range * 1e6) / 1e6
|
|
2863
|
+
})) : sorted;
|
|
2864
|
+
if (threshold !== void 0) {
|
|
2865
|
+
return normalized.filter((r) => r.score >= threshold);
|
|
2866
|
+
}
|
|
2867
|
+
return normalized;
|
|
2868
|
+
}
|
|
2842
2869
|
async vectorSearch(query, stores, limit, threshold) {
|
|
2843
2870
|
const queryVector = await this.embeddingEngine.embed(query);
|
|
2844
2871
|
const results = [];
|
|
@@ -2853,7 +2880,8 @@ var SearchService = class {
|
|
|
2853
2880
|
}))
|
|
2854
2881
|
);
|
|
2855
2882
|
}
|
|
2856
|
-
|
|
2883
|
+
const normalized = this.normalizeAndFilterScores(results, threshold);
|
|
2884
|
+
return normalized.slice(0, limit);
|
|
2857
2885
|
}
|
|
2858
2886
|
async ftsSearch(query, stores, limit) {
|
|
2859
2887
|
const results = [];
|
|
@@ -2873,7 +2901,7 @@ var SearchService = class {
|
|
|
2873
2901
|
async hybridSearch(query, stores, limit, threshold) {
|
|
2874
2902
|
const intents = classifyQueryIntents(query);
|
|
2875
2903
|
const [vectorResults, ftsResults] = await Promise.all([
|
|
2876
|
-
this.vectorSearch(query, stores, limit * 2
|
|
2904
|
+
this.vectorSearch(query, stores, limit * 2),
|
|
2877
2905
|
this.ftsSearch(query, stores, limit * 2)
|
|
2878
2906
|
]);
|
|
2879
2907
|
const vectorRanks = /* @__PURE__ */ new Map();
|
|
@@ -2927,32 +2955,41 @@ var SearchService = class {
|
|
|
2927
2955
|
});
|
|
2928
2956
|
}
|
|
2929
2957
|
const sorted = rrfScores.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
2958
|
+
let normalizedResults;
|
|
2930
2959
|
if (sorted.length > 0) {
|
|
2931
2960
|
const first = sorted[0];
|
|
2932
2961
|
const last = sorted[sorted.length - 1];
|
|
2933
2962
|
if (first === void 0 || last === void 0) {
|
|
2934
|
-
|
|
2963
|
+
normalizedResults = sorted.map((r) => ({
|
|
2935
2964
|
...r.result,
|
|
2936
2965
|
score: r.score,
|
|
2937
2966
|
rankingMetadata: r.metadata
|
|
2938
2967
|
}));
|
|
2968
|
+
} else {
|
|
2969
|
+
const maxScore = first.score;
|
|
2970
|
+
const minScore = last.score;
|
|
2971
|
+
const range = maxScore - minScore;
|
|
2972
|
+
if (range > 0) {
|
|
2973
|
+
normalizedResults = sorted.map((r) => ({
|
|
2974
|
+
...r.result,
|
|
2975
|
+
score: Math.round((r.score - minScore) / range * 1e6) / 1e6,
|
|
2976
|
+
rankingMetadata: r.metadata
|
|
2977
|
+
}));
|
|
2978
|
+
} else {
|
|
2979
|
+
normalizedResults = sorted.map((r) => ({
|
|
2980
|
+
...r.result,
|
|
2981
|
+
score: r.score,
|
|
2982
|
+
rankingMetadata: r.metadata
|
|
2983
|
+
}));
|
|
2984
|
+
}
|
|
2939
2985
|
}
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
const range = maxScore - minScore;
|
|
2943
|
-
if (range > 0) {
|
|
2944
|
-
return sorted.map((r) => ({
|
|
2945
|
-
...r.result,
|
|
2946
|
-
score: (r.score - minScore) / range,
|
|
2947
|
-
rankingMetadata: r.metadata
|
|
2948
|
-
}));
|
|
2949
|
-
}
|
|
2986
|
+
} else {
|
|
2987
|
+
normalizedResults = [];
|
|
2950
2988
|
}
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
}));
|
|
2989
|
+
if (threshold !== void 0) {
|
|
2990
|
+
return normalizedResults.filter((r) => r.score >= threshold);
|
|
2991
|
+
}
|
|
2992
|
+
return normalizedResults;
|
|
2956
2993
|
}
|
|
2957
2994
|
async searchAllStores(query, storeIds) {
|
|
2958
2995
|
return this.search({
|
|
@@ -4016,18 +4053,11 @@ var LanceStore = class {
|
|
|
4016
4053
|
const idList = documentIds.map((id) => `"${id}"`).join(", ");
|
|
4017
4054
|
await table.delete(`id IN (${idList})`);
|
|
4018
4055
|
}
|
|
4019
|
-
async search(storeId, vector, limit,
|
|
4056
|
+
async search(storeId, vector, limit, _threshold) {
|
|
4020
4057
|
const table = await this.getTable(storeId);
|
|
4021
|
-
|
|
4022
|
-
if (threshold !== void 0) {
|
|
4023
|
-
query = query.distanceType("cosine");
|
|
4024
|
-
}
|
|
4058
|
+
const query = table.vectorSearch(vector).limit(limit).distanceType("cosine");
|
|
4025
4059
|
const results = await query.toArray();
|
|
4026
|
-
return results.
|
|
4027
|
-
if (threshold === void 0) return true;
|
|
4028
|
-
const score = 1 - r._distance;
|
|
4029
|
-
return score >= threshold;
|
|
4030
|
-
}).map((r) => ({
|
|
4060
|
+
return results.map((r) => ({
|
|
4031
4061
|
id: createDocumentId(r.id),
|
|
4032
4062
|
content: r.content,
|
|
4033
4063
|
score: 1 - r._distance,
|
|
@@ -4160,4 +4190,4 @@ export {
|
|
|
4160
4190
|
createServices,
|
|
4161
4191
|
destroyServices
|
|
4162
4192
|
};
|
|
4163
|
-
//# sourceMappingURL=chunk-
|
|
4193
|
+
//# sourceMappingURL=chunk-CGDEV2RC.js.map
|