@haisto/opencode-mem 2.16.0-beta.2 → 2.16.0-beta.4
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/dist/index.js +1 -1
- package/dist/services/api-handlers.d.ts.map +1 -1
- package/dist/services/api-handlers.js +0 -1
- package/dist/services/user-memory-learning.d.ts +2 -0
- package/dist/services/user-memory-learning.d.ts.map +1 -1
- package/dist/services/user-memory-learning.js +31 -11
- package/dist/services/user-profile/profile-context.d.ts.map +1 -1
- package/dist/services/user-profile/profile-context.js +1 -38
- package/dist/services/user-profile/profile-utils.d.ts +15 -0
- package/dist/services/user-profile/profile-utils.d.ts.map +1 -1
- package/dist/services/user-profile/profile-utils.js +54 -0
- package/dist/services/user-profile/user-profile-manager.d.ts +23 -0
- package/dist/services/user-profile/user-profile-manager.d.ts.map +1 -1
- package/dist/services/user-profile/user-profile-manager.js +132 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -334,7 +334,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
334
334
|
const existingProfile = userProfileManager.getActiveProfile(userId);
|
|
335
335
|
if (existingProfile) {
|
|
336
336
|
const existingData = JSON.parse(existingProfile.profileData);
|
|
337
|
-
const mergedData = userProfileManager.
|
|
337
|
+
const mergedData = await userProfileManager.smartMergeProfileData(existingData, {
|
|
338
338
|
preferences: [newPreference],
|
|
339
339
|
});
|
|
340
340
|
userProfileManager.updateProfile(existingProfile.id, mergedData, 0, `Explicit preference added: ${sanitizedContent.slice(0, 80)}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-handlers.d.ts","sourceRoot":"","sources":["../../src/services/api-handlers.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"api-handlers.d.ts","sourceRoot":"","sources":["../../src/services/api-handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -933,7 +933,6 @@ export async function handleRunTagMigrationBatch(batchSize = 5) {
|
|
|
933
933
|
const { buildMemoryProviderConfig } = await import("./ai/provider-config.js");
|
|
934
934
|
const providerConfig = buildMemoryProviderConfig(CONFIG, {
|
|
935
935
|
maxIterations: 1,
|
|
936
|
-
iterationTimeout: 30000,
|
|
937
936
|
});
|
|
938
937
|
const provider = AIProviderFactory.createProvider(CONFIG.memoryProvider, providerConfig);
|
|
939
938
|
const projectShards = shardManager.getAllShards("project", "");
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
|
+
import type { UserProfileData } from "./user-profile/types.js";
|
|
2
3
|
export declare function performUserProfileLearning(ctx: PluginInput, directory: string): Promise<void>;
|
|
4
|
+
export declare function generateChangeSummary(oldProfile: UserProfileData, newProfile: UserProfileData): string;
|
|
3
5
|
//# sourceMappingURL=user-memory-learning.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-memory-learning.d.ts","sourceRoot":"","sources":["../../src/services/user-memory-learning.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"user-memory-learning.d.ts","sourceRoot":"","sources":["../../src/services/user-memory-learning.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAOvD,OAAO,KAAK,EAAe,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI5E,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAuEf;AAED,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,eAAe,GAAG,MAAM,CAiCtG"}
|
|
@@ -53,17 +53,37 @@ export async function performUserProfileLearning(ctx, directory) {
|
|
|
53
53
|
isLearningRunning = false;
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
-
function generateChangeSummary(oldProfile, newProfile) {
|
|
56
|
+
export function generateChangeSummary(oldProfile, newProfile) {
|
|
57
57
|
const changes = [];
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
// 新增
|
|
59
|
+
const prefAdd = newProfile.preferences.length - oldProfile.preferences.length;
|
|
60
|
+
if (prefAdd > 0)
|
|
61
|
+
changes.push(`+${prefAdd} preferences`);
|
|
62
|
+
const patternAdd = newProfile.patterns.length - oldProfile.patterns.length;
|
|
63
|
+
if (patternAdd > 0)
|
|
64
|
+
changes.push(`+${patternAdd} patterns`);
|
|
65
|
+
const workflowAdd = newProfile.workflows.length - oldProfile.workflows.length;
|
|
66
|
+
if (workflowAdd > 0)
|
|
67
|
+
changes.push(`+${workflowAdd} workflows`);
|
|
68
|
+
// 修改:按 category 匹配,检测 description 变化
|
|
69
|
+
const modifiedPrefs = newProfile.preferences.filter((p) => {
|
|
70
|
+
const old = oldProfile.preferences.find((o) => o.category === p.category);
|
|
71
|
+
return old && old.description !== p.description;
|
|
72
|
+
}).length;
|
|
73
|
+
if (modifiedPrefs > 0)
|
|
74
|
+
changes.push(`${modifiedPrefs} preferences modified`);
|
|
75
|
+
const modifiedPatterns = newProfile.patterns.filter((p) => {
|
|
76
|
+
const old = oldProfile.patterns.find((o) => o.category === p.category);
|
|
77
|
+
return old && old.description !== p.description;
|
|
78
|
+
}).length;
|
|
79
|
+
if (modifiedPatterns > 0)
|
|
80
|
+
changes.push(`${modifiedPatterns} patterns modified`);
|
|
81
|
+
const modifiedWorkflows = newProfile.workflows.filter((w) => {
|
|
82
|
+
const old = oldProfile.workflows.find((o) => o.description === w.description);
|
|
83
|
+
return old && old.steps && w.steps && JSON.stringify(old.steps) !== JSON.stringify(w.steps);
|
|
84
|
+
}).length;
|
|
85
|
+
if (modifiedWorkflows > 0)
|
|
86
|
+
changes.push(`${modifiedWorkflows} workflows modified`);
|
|
67
87
|
return changes.length > 0 ? changes.join(", ") : "Profile refinement";
|
|
68
88
|
}
|
|
69
89
|
function buildUserAnalysisContext(prompts, existingProfile) {
|
|
@@ -235,7 +255,7 @@ Use the update_user_profile tool to save the ${existingProfile ? "updated" : "ne
|
|
|
235
255
|
const rawData = result.data;
|
|
236
256
|
if (existingProfile) {
|
|
237
257
|
const existingData = JSON.parse(existingProfile.profileData);
|
|
238
|
-
return userProfileManager.
|
|
258
|
+
return await userProfileManager.smartMergeProfileData(existingData, rawData);
|
|
239
259
|
}
|
|
240
260
|
return rawData;
|
|
241
261
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile-context.d.ts","sourceRoot":"","sources":["../../../src/services/user-profile/profile-context.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"profile-context.d.ts","sourceRoot":"","sources":["../../../src/services/user-profile/profile-context.ts"],"names":[],"mappings":"AA8DA,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoDzF"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { userProfileManager } from "./user-profile-manager.js";
|
|
2
2
|
import { CONFIG } from "../../config.js";
|
|
3
|
+
import { extractTerms } from "./profile-utils.js";
|
|
3
4
|
/**
|
|
4
5
|
* Compute relevance score between a query and a target text.
|
|
5
6
|
* Uses term overlap across all languages via Intl.Segmenter + CJK bigrams.
|
|
@@ -17,44 +18,6 @@ function computeRelevance(query, target) {
|
|
|
17
18
|
}
|
|
18
19
|
return matches / terms.length;
|
|
19
20
|
}
|
|
20
|
-
/**
|
|
21
|
-
* Extract indexable terms from text, supporting all languages.
|
|
22
|
-
*
|
|
23
|
-
* Strategy:
|
|
24
|
-
* 1. Intl.Segmenter (word granularity) across the whole text — captures
|
|
25
|
-
* words/identifiers in any script (Latin, Arabic, Cyrillic, Devanagari, etc.)
|
|
26
|
-
* 2. CJK bigram pass — adds adjacent pairs of CJK characters because word
|
|
27
|
-
* segmenters often under-split Chinese/Japanese/Korean text.
|
|
28
|
-
* 3. All terms are lowercased, deduplicated, and must be >= 2 characters.
|
|
29
|
-
*/
|
|
30
|
-
function extractTerms(text) {
|
|
31
|
-
const terms = new Set();
|
|
32
|
-
// Step 1: Intl.Segmenter — works for all languages
|
|
33
|
-
try {
|
|
34
|
-
const segmenter = new Intl.Segmenter("zh", { granularity: "word" });
|
|
35
|
-
for (const seg of segmenter.segment(text)) {
|
|
36
|
-
const word = seg.segment.toLowerCase();
|
|
37
|
-
if (seg.isWordLike && word.length >= 2) {
|
|
38
|
-
terms.add(word);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
// Intl.Segmenter not available (very old runtime), fallback to simple regex
|
|
44
|
-
const words = text.toLowerCase().match(/[a-z][a-z0-9_]{2,}/g);
|
|
45
|
-
if (words)
|
|
46
|
-
words.forEach((w) => terms.add(w));
|
|
47
|
-
}
|
|
48
|
-
// Step 2: CJK bigram — catches sub-word units in CJK text
|
|
49
|
-
const cjkChars = [...text].filter((ch) => /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u.test(ch));
|
|
50
|
-
if (cjkChars.length > 1) {
|
|
51
|
-
for (let i = 0; i < cjkChars.length - 1; i++) {
|
|
52
|
-
const bigram = (cjkChars[i] + cjkChars[i + 1]).toLowerCase();
|
|
53
|
-
terms.add(bigram);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return Array.from(terms);
|
|
57
|
-
}
|
|
58
21
|
/**
|
|
59
22
|
* Filter items by relevance to query.
|
|
60
23
|
* When query is empty/undefined, returns top items (must be pre-sorted).
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract indexable terms from text, supporting all languages.
|
|
3
|
+
*
|
|
4
|
+
* Strategy:
|
|
5
|
+
* 1. Intl.Segmenter (word granularity) across the whole text — captures
|
|
6
|
+
* words/identifiers in any script (Latin, Arabic, Cyrillic, Devanagari, etc.)
|
|
7
|
+
* 2. CJK bigram pass — adds adjacent pairs of CJK characters because word
|
|
8
|
+
* segmenters often under-split Chinese/Japanese/Korean text.
|
|
9
|
+
* 3. All terms are lowercased, deduplicated, and must be >= 2 characters.
|
|
10
|
+
*/
|
|
11
|
+
export declare function extractTerms(text: string): string[];
|
|
12
|
+
/**
|
|
13
|
+
* Jaccard similarity between two texts based on extracted terms (0-1).
|
|
14
|
+
*/
|
|
15
|
+
export declare function computeTermOverlap(text1: string, text2: string): number;
|
|
1
16
|
export declare const safeArray: <T>(arr: any) => T[];
|
|
2
17
|
export declare const safeObject: <T extends object>(obj: any, fallback: T) => T;
|
|
3
18
|
//# sourceMappingURL=profile-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile-utils.d.ts","sourceRoot":"","sources":["../../../src/services/user-profile/profile-utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,KAAK,GAAG,KAAG,CAAC,EA0BxC,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,MAAM,EAAE,KAAK,GAAG,EAAE,UAAU,CAAC,KAAG,CAWpE,CAAC"}
|
|
1
|
+
{"version":3,"file":"profile-utils.d.ts","sourceRoot":"","sources":["../../../src/services/user-profile/profile-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA8BnD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAYvE;AAED,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,KAAK,GAAG,KAAG,CAAC,EA0BxC,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,MAAM,EAAE,KAAK,GAAG,EAAE,UAAU,CAAC,KAAG,CAWpE,CAAC"}
|
|
@@ -1,3 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract indexable terms from text, supporting all languages.
|
|
3
|
+
*
|
|
4
|
+
* Strategy:
|
|
5
|
+
* 1. Intl.Segmenter (word granularity) across the whole text — captures
|
|
6
|
+
* words/identifiers in any script (Latin, Arabic, Cyrillic, Devanagari, etc.)
|
|
7
|
+
* 2. CJK bigram pass — adds adjacent pairs of CJK characters because word
|
|
8
|
+
* segmenters often under-split Chinese/Japanese/Korean text.
|
|
9
|
+
* 3. All terms are lowercased, deduplicated, and must be >= 2 characters.
|
|
10
|
+
*/
|
|
11
|
+
export function extractTerms(text) {
|
|
12
|
+
const terms = new Set();
|
|
13
|
+
// Step 1: Intl.Segmenter — works for all languages
|
|
14
|
+
try {
|
|
15
|
+
const segmenter = new Intl.Segmenter("zh", { granularity: "word" });
|
|
16
|
+
for (const seg of segmenter.segment(text)) {
|
|
17
|
+
const word = seg.segment.toLowerCase();
|
|
18
|
+
if (seg.isWordLike && word.length >= 2) {
|
|
19
|
+
terms.add(word);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Intl.Segmenter not available (very old runtime), fallback to simple regex
|
|
25
|
+
const words = text.toLowerCase().match(/[a-z][a-z0-9_]{2,}/g);
|
|
26
|
+
if (words)
|
|
27
|
+
words.forEach((w) => terms.add(w));
|
|
28
|
+
}
|
|
29
|
+
// Step 2: CJK bigram — catches sub-word units in CJK text
|
|
30
|
+
const cjkChars = [...text].filter((ch) => /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u.test(ch));
|
|
31
|
+
if (cjkChars.length > 1) {
|
|
32
|
+
for (let i = 0; i < cjkChars.length - 1; i++) {
|
|
33
|
+
const bigram = (cjkChars[i] + cjkChars[i + 1]).toLowerCase();
|
|
34
|
+
terms.add(bigram);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return Array.from(terms);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Jaccard similarity between two texts based on extracted terms (0-1).
|
|
41
|
+
*/
|
|
42
|
+
export function computeTermOverlap(text1, text2) {
|
|
43
|
+
const t1 = new Set(extractTerms(text1));
|
|
44
|
+
const t2 = new Set(extractTerms(text2));
|
|
45
|
+
if (t1.size === 0 || t2.size === 0)
|
|
46
|
+
return 0;
|
|
47
|
+
let intersection = 0;
|
|
48
|
+
for (const t of t1) {
|
|
49
|
+
if (t2.has(t))
|
|
50
|
+
intersection++;
|
|
51
|
+
}
|
|
52
|
+
const union = new Set([...t1, ...t2]);
|
|
53
|
+
return intersection / union.size;
|
|
54
|
+
}
|
|
1
55
|
export const safeArray = (arr) => {
|
|
2
56
|
if (!arr)
|
|
3
57
|
return [];
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { UserProfile, UserProfileChangelog, UserProfileData } from "./types.js";
|
|
2
|
+
export type MatchCallback = (items: {
|
|
3
|
+
category: string;
|
|
4
|
+
description: string;
|
|
5
|
+
}[], newItem: {
|
|
6
|
+
category: string;
|
|
7
|
+
description: string;
|
|
8
|
+
}, itemType: "preference" | "pattern" | "workflow") => Promise<number>;
|
|
2
9
|
export declare class UserProfileManager {
|
|
3
10
|
private db;
|
|
4
11
|
private readonly dbPath;
|
|
@@ -24,6 +31,22 @@ export declare class UserProfileManager {
|
|
|
24
31
|
private rowToProfile;
|
|
25
32
|
private rowToChangelog;
|
|
26
33
|
mergeProfileData(existing: UserProfileData, updates: Partial<UserProfileData>): UserProfileData;
|
|
34
|
+
/**
|
|
35
|
+
* Find the best semiically similar match in existing items using term overlap.
|
|
36
|
+
* Returns the index of the best match, or -1 if no match exceeds the threshold.
|
|
37
|
+
*/
|
|
38
|
+
private findSemanticMatch;
|
|
39
|
+
/**
|
|
40
|
+
* Smart merge: tries LLM matching (via optional callback), falls back to term overlap.
|
|
41
|
+
*
|
|
42
|
+
* For matched items: merges in-place (updates description, confidence,
|
|
43
|
+
* evidence, lastUpdated) — the incoming description becomes the latest.
|
|
44
|
+
* For unmatched items: delegates to mergeProfileData for normal addition.
|
|
45
|
+
*
|
|
46
|
+
* This ensures that manual writes (e.g. "50年经验" → "20年") update
|
|
47
|
+
* the description content instead of being overwritten by the redirect.
|
|
48
|
+
*/
|
|
49
|
+
smartMergeProfileData(existing: UserProfileData, updates: Partial<UserProfileData>, llmMatch?: MatchCallback): Promise<UserProfileData>;
|
|
27
50
|
private ensureArray;
|
|
28
51
|
}
|
|
29
52
|
export declare const userProfileManager: UserProfileManager;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-profile-manager.d.ts","sourceRoot":"","sources":["../../../src/services/user-profile/user-profile-manager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AASrF,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,EAAE,CAAe;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;;IAQhC,OAAO,CAAC,YAAY;IA0CpB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAapD,aAAa,CACX,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,eAAe,EAC5B,eAAe,EAAE,MAAM,GACtB,MAAM;IAoCT,aAAa,CACX,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,eAAe,EAC5B,yBAAyB,EAAE,MAAM,EACjC,aAAa,EAAE,MAAM,GACpB,IAAI;IAmCP;;;OAGG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAgB7D,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAgB1D,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAgB3D,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,oBAAoB;IAiB5B,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,oBAAoB,EAAE;IAYnF,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IA+F7C,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKtC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAOrD,oBAAoB,IAAI,WAAW,EAAE;IAMrC,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,cAAc;IAYtB,gBAAgB,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe;IAsG/F,OAAO,CAAC,WAAW;CAWpB;AAED,eAAO,MAAM,kBAAkB,oBAA2B,CAAC"}
|
|
1
|
+
{"version":3,"file":"user-profile-manager.d.ts","sourceRoot":"","sources":["../../../src/services/user-profile/user-profile-manager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AASrF,MAAM,MAAM,aAAa,GAAG,CAC1B,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EAAE,EAClD,OAAO,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EAClD,QAAQ,EAAE,YAAY,GAAG,SAAS,GAAG,UAAU,KAC5C,OAAO,CAAC,MAAM,CAAC,CAAC;AAErB,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,EAAE,CAAe;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;;IAQhC,OAAO,CAAC,YAAY;IA0CpB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAapD,aAAa,CACX,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,eAAe,EAC5B,eAAe,EAAE,MAAM,GACtB,MAAM;IAoCT,aAAa,CACX,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,eAAe,EAC5B,yBAAyB,EAAE,MAAM,EACjC,aAAa,EAAE,MAAM,GACpB,IAAI;IAmCP;;;OAGG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAgB7D,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAgB1D,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAgB3D,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,oBAAoB;IAiB5B,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,oBAAoB,EAAE;IAYnF,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IA+F7C,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKtC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAOrD,oBAAoB,IAAI,WAAW,EAAE;IAMrC,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,cAAc;IAYtB,gBAAgB,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe;IAsG/F;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IA6BzB;;;;;;;;;OASG;IACG,qBAAqB,CACzB,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,EACjC,QAAQ,CAAC,EAAE,aAAa,GACvB,OAAO,CAAC,eAAe,CAAC;IAgH3B,OAAO,CAAC,WAAW;CAWpB;AAED,eAAO,MAAM,kBAAkB,oBAA2B,CAAC"}
|
|
@@ -2,7 +2,7 @@ import { getDatabase } from "../sqlite/sqlite-bootstrap.js";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { connectionManager } from "../sqlite/connection-manager.js";
|
|
4
4
|
import { CONFIG } from "../../config.js";
|
|
5
|
-
import { safeArray, safeObject } from "./profile-utils.js";
|
|
5
|
+
import { safeArray, safeObject, computeTermOverlap } from "./profile-utils.js";
|
|
6
6
|
import { log, logTrace } from "../logger.js";
|
|
7
7
|
const Database = getDatabase();
|
|
8
8
|
const USER_PROFILES_DB_NAME = "user-profiles.db";
|
|
@@ -395,6 +395,137 @@ export class UserProfileManager {
|
|
|
395
395
|
}
|
|
396
396
|
return merged;
|
|
397
397
|
}
|
|
398
|
+
/**
|
|
399
|
+
* Find the best semiically similar match in existing items using term overlap.
|
|
400
|
+
* Returns the index of the best match, or -1 if no match exceeds the threshold.
|
|
401
|
+
*/
|
|
402
|
+
findSemanticMatch(items, newItem, getText, threshold = 0.3) {
|
|
403
|
+
const newText = getText(newItem);
|
|
404
|
+
if (!newText || newText.length < 5)
|
|
405
|
+
return -1;
|
|
406
|
+
let bestIndex = -1;
|
|
407
|
+
let bestScore = threshold;
|
|
408
|
+
for (let i = 0; i < items.length; i++) {
|
|
409
|
+
const existingText = getText(items[i]);
|
|
410
|
+
if (!existingText)
|
|
411
|
+
continue;
|
|
412
|
+
// Exact match → immediate return
|
|
413
|
+
if (existingText === newText)
|
|
414
|
+
return i;
|
|
415
|
+
const score = computeTermOverlap(newText, existingText);
|
|
416
|
+
if (score > bestScore) {
|
|
417
|
+
bestScore = score;
|
|
418
|
+
bestIndex = i;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return bestIndex;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Smart merge: tries LLM matching (via optional callback), falls back to term overlap.
|
|
425
|
+
*
|
|
426
|
+
* For matched items: merges in-place (updates description, confidence,
|
|
427
|
+
* evidence, lastUpdated) — the incoming description becomes the latest.
|
|
428
|
+
* For unmatched items: delegates to mergeProfileData for normal addition.
|
|
429
|
+
*
|
|
430
|
+
* This ensures that manual writes (e.g. "50年经验" → "20年") update
|
|
431
|
+
* the description content instead of being overwritten by the redirect.
|
|
432
|
+
*/
|
|
433
|
+
async smartMergeProfileData(existing, updates, llmMatch) {
|
|
434
|
+
// Clone existing — we'll mutate this and fall through matched items
|
|
435
|
+
const result = {
|
|
436
|
+
preferences: [...this.ensureArray(existing?.preferences)],
|
|
437
|
+
patterns: [...this.ensureArray(existing?.patterns)],
|
|
438
|
+
workflows: [...this.ensureArray(existing?.workflows)],
|
|
439
|
+
};
|
|
440
|
+
const unmatched = {
|
|
441
|
+
preferences: [],
|
|
442
|
+
patterns: [],
|
|
443
|
+
workflows: [],
|
|
444
|
+
};
|
|
445
|
+
// --- preferences ---
|
|
446
|
+
if (updates.preferences) {
|
|
447
|
+
for (const pref of updates.preferences) {
|
|
448
|
+
let idx = this.findSemanticMatch(result.preferences, pref, (p) => `${p.category} ${p.description}`, 0.4);
|
|
449
|
+
if (idx < 0 && llmMatch) {
|
|
450
|
+
idx = await llmMatch(result.preferences, pref, "preference");
|
|
451
|
+
}
|
|
452
|
+
if (idx >= 0 && result.preferences[idx]) {
|
|
453
|
+
const target = result.preferences[idx];
|
|
454
|
+
result.preferences[idx] = {
|
|
455
|
+
category: target.category,
|
|
456
|
+
description: pref.description, // ← latest content wins
|
|
457
|
+
confidence: Math.max(pref.confidence ?? 0, target.confidence ?? 0),
|
|
458
|
+
evidence: [
|
|
459
|
+
...new Set([
|
|
460
|
+
...this.ensureArray(target.evidence),
|
|
461
|
+
...this.ensureArray(pref.evidence),
|
|
462
|
+
]),
|
|
463
|
+
].slice(0, 5),
|
|
464
|
+
lastUpdated: Date.now(),
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
unmatched.preferences.push(pref);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
// --- patterns ---
|
|
473
|
+
if (updates.patterns) {
|
|
474
|
+
for (const pattern of updates.patterns) {
|
|
475
|
+
let idx = this.findSemanticMatch(result.patterns, pattern, (p) => `${p.category} ${p.description}`, 0.4);
|
|
476
|
+
if (idx < 0 && llmMatch) {
|
|
477
|
+
idx = await llmMatch(result.patterns, pattern, "pattern");
|
|
478
|
+
}
|
|
479
|
+
if (idx >= 0 && result.patterns[idx]) {
|
|
480
|
+
const target = result.patterns[idx];
|
|
481
|
+
const newFreq = Math.max((pattern.frequency || 0), (target.frequency || 1) + 1);
|
|
482
|
+
result.patterns[idx] = {
|
|
483
|
+
category: target.category,
|
|
484
|
+
description: pattern.description, // latest content wins
|
|
485
|
+
frequency: newFreq,
|
|
486
|
+
lastSeen: Date.now(),
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
unmatched.patterns.push(pattern);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
// --- workflows ---
|
|
495
|
+
if (updates.workflows) {
|
|
496
|
+
for (const wf of updates.workflows) {
|
|
497
|
+
let idx = this.findSemanticMatch(result.workflows, wf, (w) => w.description, 0.4);
|
|
498
|
+
if (idx < 0 && llmMatch) {
|
|
499
|
+
idx = await llmMatch(result.workflows.map((w) => ({ category: "", description: w.description })), { category: "", description: wf.description }, "workflow");
|
|
500
|
+
}
|
|
501
|
+
if (idx >= 0 && result.workflows[idx]) {
|
|
502
|
+
const target = result.workflows[idx];
|
|
503
|
+
const newFreq = Math.max((wf.frequency || 0), (target.frequency || 1) + 1);
|
|
504
|
+
result.workflows[idx] = {
|
|
505
|
+
...target,
|
|
506
|
+
description: wf.description, // latest content wins
|
|
507
|
+
frequency: newFreq,
|
|
508
|
+
lastSeen: Date.now(),
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
unmatched.workflows.push(wf);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
// Send unmatched items through mergeProfileData for normal addition
|
|
517
|
+
const hasUnmatched = unmatched.preferences.length > 0 ||
|
|
518
|
+
unmatched.patterns.length > 0 ||
|
|
519
|
+
unmatched.workflows.length > 0;
|
|
520
|
+
if (hasUnmatched) {
|
|
521
|
+
return this.mergeProfileData(result, {
|
|
522
|
+
preferences: unmatched.preferences.length > 0 ? unmatched.preferences : undefined,
|
|
523
|
+
patterns: unmatched.patterns.length > 0 ? unmatched.patterns : undefined,
|
|
524
|
+
workflows: unmatched.workflows.length > 0 ? unmatched.workflows : undefined,
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
return result;
|
|
528
|
+
}
|
|
398
529
|
ensureArray(val) {
|
|
399
530
|
if (typeof val === "string") {
|
|
400
531
|
try {
|
package/package.json
CHANGED