@scotthuang/engram 0.7.5 → 0.8.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.
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 晋升评分引擎模拟测试
3
+ *
4
+ * 使用真实的 recall-hits.json 数据,模拟 6 维评分 + 筛选,不执行真实晋升
5
+ */
6
+ export {};
@@ -0,0 +1,105 @@
1
+ /**
2
+ * 晋升评分引擎模拟测试
3
+ *
4
+ * 使用真实的 recall-hits.json 数据,模拟 6 维评分 + 筛选,不执行真实晋升
5
+ */
6
+ import { readFileSync } from "node:fs";
7
+ import { join } from "node:path";
8
+ // 直接导入 promotion 模块
9
+ import { rankPromotionCandidates, filterPromotionCandidates, PROMOTION_PRESETS, DEFAULT_WEIGHTS, } from "../promotion.js";
10
+ // ---- 加载真实数据 ----
11
+ const WORKSPACE = process.env.WORKSPACE_DIR || join(process.env.HOME || "", ".openclaw/workspace");
12
+ const recallHitsPath = join(WORKSPACE, "memory-engram", "recall-hits.json");
13
+ let hits;
14
+ try {
15
+ const raw = readFileSync(recallHitsPath, "utf-8");
16
+ const parsed = JSON.parse(raw);
17
+ hits = {};
18
+ for (const [key, value] of Object.entries(parsed)) {
19
+ if (typeof value === "number") {
20
+ hits[key] = { recallCount: 1, firstHit: value, lastHit: value, settled: false, queryHashes: [], recallDays: [], totalScore: 0, maxScore: 0, dailyCount: 0, conceptTags: [] };
21
+ }
22
+ else if (typeof value === "object" && value !== null) {
23
+ const entry = value;
24
+ if (entry.recallCount == null && entry.hitCount != null) {
25
+ entry.recallCount = entry.hitCount;
26
+ }
27
+ if (entry.recallCount == null)
28
+ entry.recallCount = 0;
29
+ if (!entry.queryHashes)
30
+ entry.queryHashes = [];
31
+ if (!entry.recallDays)
32
+ entry.recallDays = [];
33
+ if (entry.totalScore == null)
34
+ entry.totalScore = 0;
35
+ if (entry.maxScore == null)
36
+ entry.maxScore = 0;
37
+ if (entry.dailyCount == null)
38
+ entry.dailyCount = 0;
39
+ if (!entry.conceptTags)
40
+ entry.conceptTags = [];
41
+ hits[key] = entry;
42
+ }
43
+ }
44
+ }
45
+ catch (err) {
46
+ console.error(`Failed to load ${recallHitsPath}: ${err}`);
47
+ process.exit(1);
48
+ }
49
+ console.log("═══════════════════════════════════════════════════════════════");
50
+ console.log(" Engram 晋升评分模拟测试(Dry-Run)");
51
+ console.log("═══════════════════════════════════════════════════════════════");
52
+ console.log(`\n数据源: ${recallHitsPath}`);
53
+ console.log(`总条目: ${Object.keys(hits).length}`);
54
+ console.log(`已晋升: ${Object.values(hits).filter(e => e.settled || e.promotedAt).length}`);
55
+ console.log(`权重: ${JSON.stringify(DEFAULT_WEIGHTS)}`);
56
+ // ---- 排名 ----
57
+ const ranked = rankPromotionCandidates(hits);
58
+ console.log(`\n─── 全部候选排名(${ranked.length} 条)───\n`);
59
+ console.log("排名 | 文件名 | 综合分 | freq | rel | div | rec | cons | conc | rcl | sig | queries | days | age(d)");
60
+ console.log("─────┼────────────────────┼─────────┼────────┼────────┼────────┼────────┼────────┼────────┼──────┼──────┼─────────┼──────┼───────");
61
+ for (let i = 0; i < ranked.length; i++) {
62
+ const c = ranked[i];
63
+ const w = DEFAULT_WEIGHTS;
64
+ console.log(` ${String(i + 1).padStart(2)} | ${c.key.padEnd(18)} | ${c.score.toFixed(4).padStart(7)} | ` +
65
+ `${(c.components.frequency * w.frequency).toFixed(3).padStart(6)} | ` +
66
+ `${(c.components.relevance * w.relevance).toFixed(3).padStart(6)} | ` +
67
+ `${(c.components.diversity * w.diversity).toFixed(3).padStart(6)} | ` +
68
+ `${(c.components.recency * w.recency).toFixed(3).padStart(6)} | ` +
69
+ `${(c.components.consolidation * w.consolidation).toFixed(3).padStart(6)} | ` +
70
+ `${(c.components.conceptual * DEFAULT_WEIGHTS.conceptual).toFixed(3).padStart(6)} | ` +
71
+ `${String(c.recallCount).padStart(4)} | ${String(c.signalCount).padStart(4)} | ${String(c.uniqueQueries).padStart(7)} | ${String(c.uniqueDays).padStart(4)} | ${c.ageDays.toFixed(1).padStart(6)}`);
72
+ }
73
+ // ---- 三档预设筛选 ----
74
+ for (const mode of ["core", "deep", "rem"]) {
75
+ const preset = PROMOTION_PRESETS[mode];
76
+ const config = { mode, ...preset };
77
+ const eligible = filterPromotionCandidates(ranked, config);
78
+ console.log(`\n─── ${mode.toUpperCase()} 模式筛选结果(minScore=${config.minScore}, minHits=${config.minRecallCount}, minQueries=${config.minUniqueQueries})───`);
79
+ if (eligible.length === 0) {
80
+ console.log(" (无候选通过筛选)");
81
+ }
82
+ else {
83
+ for (const c of eligible) {
84
+ console.log(` ✓ ${c.key} score=${c.score.toFixed(4)} signals=${c.signalCount} recalls=${c.recallCount} queries=${c.uniqueQueries} days=${c.uniqueDays}`);
85
+ }
86
+ }
87
+ console.log(` 总计: ${eligible.length} / ${ranked.length} 通过`);
88
+ }
89
+ // ---- 分析旧数据特征 ----
90
+ console.log("\n─── 旧数据分析 ───\n");
91
+ const noQueryData = ranked.filter(c => c.uniqueQueries === 0);
92
+ const noScoreData = ranked.filter(c => c.avgScore === 0);
93
+ const noTagData = ranked.filter(c => {
94
+ const entry = hits[c.key];
95
+ return !entry.conceptTags || entry.conceptTags.length === 0;
96
+ });
97
+ console.log(`无 queryHashes 数据: ${noQueryData.length} / ${ranked.length} (diversity 维度=0)`);
98
+ console.log(`无 totalScore 数据: ${noScoreData.length} / ${ranked.length} (relevance 维度=0)`);
99
+ console.log(`无 conceptTags 数据: ${noTagData.length} / ${ranked.length} (conceptual 维度=0.5 fallback)`);
100
+ console.log(`\n结论: 旧数据只有 frequency + recency 两个维度有效值,其余均为默认值。`);
101
+ console.log(`随着 0.8.0 积累新的 recall 数据(queryHashes, scores, #tags),评分精度会逐步提升。`);
102
+ console.log("\n═══════════════════════════════════════════════════════════════");
103
+ console.log(" 模拟完成(未执行任何写入操作)");
104
+ console.log("═══════════════════════════════════════════════════════════════\n");
105
+ //# sourceMappingURL=promotion-dryrun.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promotion-dryrun.js","sourceRoot":"","sources":["../../../src/__tests__/promotion-dryrun.ts"],"names":[],"mappings":"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"}
@@ -41,6 +41,27 @@ export type MemorySystemConfig = {
41
41
  lancedbDir?: string;
42
42
  /** 是否保存中间文件(staging)供调试,默认 true */
43
43
  saveStagingFile?: boolean;
44
+ /** 跳过记忆召回的 session 规则(用于 cron/自动化任务) */
45
+ skipRecall: {
46
+ /** 前缀匹配:sessionKey 以这些前缀开头时跳过召回 */
47
+ sessionPrefixes: string[];
48
+ /** 正则匹配:sessionKey 匹配这些正则时跳过召回 */
49
+ sessionPatterns: string[];
50
+ /** 精确匹配:sessionKey 等于这些值时跳过召回 */
51
+ sessionExact: string[];
52
+ };
53
+ /** 晋升评分配置 */
54
+ promotion: {
55
+ /** 晋升模式:off 禁用 | core 每天3am | rem 每6h | deep 每12h */
56
+ mode: "off" | "core" | "rem" | "deep";
57
+ /** 每次晋升上限,默认 10 */
58
+ limit: number;
59
+ };
44
60
  };
45
61
  export declare const DEFAULTS: MemorySystemConfig;
62
+ /**
63
+ * 检查 sessionKey 是否应该跳过记忆召回
64
+ * 匹配规则:前缀匹配 OR 正则匹配 OR 精确匹配
65
+ */
66
+ export declare function shouldSkipRecallForSession(sessionKey: string | undefined, skipRecall: MemorySystemConfig["skipRecall"]): boolean;
46
67
  export declare function parseConfig(raw?: Record<string, unknown>): MemorySystemConfig;
@@ -25,7 +25,74 @@ export const DEFAULTS = {
25
25
  enabled: false,
26
26
  timeoutMs: 10000,
27
27
  },
28
+ skipRecall: {
29
+ sessionPrefixes: ["cron:", "automated:", "system:"],
30
+ sessionPatterns: [],
31
+ sessionExact: [],
32
+ },
33
+ promotion: {
34
+ mode: "rem",
35
+ limit: 10,
36
+ },
28
37
  };
38
+ function parseStringArray(value) {
39
+ if (Array.isArray(value)) {
40
+ return value.filter((v) => typeof v === "string" && v.trim().length > 0).map(v => v.trim());
41
+ }
42
+ return [];
43
+ }
44
+ function parseSkipRecallConfig(prefixes, patterns, exact) {
45
+ return {
46
+ sessionPrefixes: parseStringArray(prefixes).length > 0
47
+ ? parseStringArray(prefixes)
48
+ : DEFAULTS.skipRecall.sessionPrefixes,
49
+ sessionPatterns: parseStringArray(patterns),
50
+ sessionExact: parseStringArray(exact),
51
+ };
52
+ }
53
+ function parsePromotionConfig(raw) {
54
+ if (typeof raw === "object" && raw !== null) {
55
+ const obj = raw;
56
+ const validModes = ["off", "core", "rem", "deep"];
57
+ const mode = typeof obj.mode === "string" && validModes.includes(obj.mode)
58
+ ? obj.mode
59
+ : DEFAULTS.promotion.mode;
60
+ const limit = typeof obj.limit === "number" && obj.limit > 0
61
+ ? obj.limit
62
+ : DEFAULTS.promotion.limit;
63
+ return { mode, limit };
64
+ }
65
+ return { ...DEFAULTS.promotion };
66
+ }
67
+ /**
68
+ * 检查 sessionKey 是否应该跳过记忆召回
69
+ * 匹配规则:前缀匹配 OR 正则匹配 OR 精确匹配
70
+ */
71
+ export function shouldSkipRecallForSession(sessionKey, skipRecall) {
72
+ if (!sessionKey)
73
+ return false;
74
+ // 前缀匹配
75
+ for (const prefix of skipRecall.sessionPrefixes) {
76
+ if (sessionKey.startsWith(prefix))
77
+ return true;
78
+ }
79
+ // 精确匹配
80
+ for (const exact of skipRecall.sessionExact) {
81
+ if (sessionKey === exact)
82
+ return true;
83
+ }
84
+ // 正则匹配
85
+ for (const pattern of skipRecall.sessionPatterns) {
86
+ try {
87
+ if (new RegExp(pattern).test(sessionKey))
88
+ return true;
89
+ }
90
+ catch {
91
+ // 无效正则,跳过
92
+ }
93
+ }
94
+ return false;
95
+ }
29
96
  export function parseConfig(raw) {
30
97
  if (!raw) {
31
98
  logger.info(`[engram:config] No raw config provided, using defaults`);
@@ -70,11 +137,15 @@ export function parseConfig(raw) {
70
137
  lancedbDir: typeof raw.lancedbDir === "string" ? raw.lancedbDir : undefined,
71
138
  logDir: typeof raw.logDir === "string" ? raw.logDir : undefined,
72
139
  saveStagingFile: typeof raw.saveStagingFile === "boolean" ? raw.saveStagingFile : true,
140
+ skipRecall: parseSkipRecallConfig(raw.skipRecallSessionPrefixes, raw.skipRecallSessionPatterns, raw.skipRecallSessionExact),
141
+ promotion: parsePromotionConfig(raw.promotion),
73
142
  };
74
143
  logger.info(`[engram:config] Parsed: shortTermDays=${config.shortTermDays} halfLifeDays=${config.halfLifeDays} recallTopK=${config.recallTopK} vectorWeight=${config.vectorWeight} textWeight=${config.textWeight}`);
75
144
  logger.info(`[engram:config] Embedding: model=${config.embedding.model} dims=${config.embedding.dimensions} hasApiKey=${!!config.embedding.apiKey} baseUrl=${config.embedding.baseUrl.slice(0, 40)}`);
76
145
  logger.info(`[engram:config] Condense: model=${config.condense.model} hasApiKey=${!!config.condense.apiKey}`);
77
146
  logger.info(`[engram:config] QueryRewrite: enabled=${config.queryRewrite.enabled} timeoutMs=${config.queryRewrite.timeoutMs}`);
147
+ logger.info(`[engram:config] SkipRecall: prefixes=[${config.skipRecall.sessionPrefixes.join(",")}] patterns=[${config.skipRecall.sessionPatterns.join(",")}] exact=[${config.skipRecall.sessionExact.join(",")}]`);
148
+ logger.info(`[engram:config] Promotion: mode=${config.promotion.mode} limit=${config.promotion.limit}`);
78
149
  logger.info(`[engram:config] LogDir: ${config.logDir || "(none, console only)"}`);
79
150
  return config;
80
151
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AA4CrC,MAAM,CAAC,MAAM,QAAQ,GAAuB;IAC1C,aAAa,EAAE,EAAE;IACjB,YAAY,EAAE,EAAE;IAChB,UAAU,EAAE,CAAC;IACb,YAAY,EAAE,GAAG;IACjB,UAAU,EAAE,GAAG;IACf,WAAW,EAAE,wBAAwB;IACrC,cAAc,EAAE,mBAAmB;IACnC,SAAS,EAAE;QACT,KAAK,EAAE,mBAAmB;QAC1B,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,EAAE;QACX,UAAU,EAAE,IAAI;KACjB;IACD,QAAQ,EAAE;QACR,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,oCAAoC;QAC7C,KAAK,EAAE,wBAAwB;KAChC;IACD,YAAY,EAAE;QACZ,OAAO,EAAE,KAAK;QACd,SAAS,EAAE,KAAK;KACjB;CACF,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,GAA6B;IACvD,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;QACtE,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC;IACzB,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,yCAAyC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrF,MAAM,SAAS,GAAG,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,IAAI,GAAG,CAAC,SAAS,KAAK,IAAI;QAC3E,CAAC,CAAC;YACE,KAAK,EAAE,OAAQ,GAAG,CAAC,SAAiB,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,SAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK;YACjH,MAAM,EAAE,OAAQ,GAAG,CAAC,SAAiB,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,SAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM;YACrH,OAAO,EAAE,OAAQ,GAAG,CAAC,SAAiB,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,SAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO;YACzH,UAAU,EAAE,OAAQ,GAAG,CAAC,SAAiB,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,SAAiB,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU;SACtI;QACH,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC;IACvB,MAAM,QAAQ,GAAG,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,IAAI;QACxE,CAAC,CAAC;YACE,MAAM,EAAE,OAAQ,GAAG,CAAC,QAAgB,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,QAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM;YAClH,OAAO,EAAE,OAAQ,GAAG,CAAC,QAAgB,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,QAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO;YACtH,KAAK,EAAE,OAAQ,GAAG,CAAC,QAAgB,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,QAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK;SAC/G;QACH,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;IACtB,MAAM,YAAY,GAAG,OAAO,GAAG,CAAC,YAAY,KAAK,QAAQ,IAAI,GAAG,CAAC,YAAY,KAAK,IAAI;QACpF,CAAC,CAAC;YACE,OAAO,EAAE,OAAQ,GAAG,CAAC,YAAoB,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAE,GAAG,CAAC,YAAoB,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,OAAO;YACnI,MAAM,EAAE,OAAQ,GAAG,CAAC,YAAoB,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,YAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;YAC3G,OAAO,EAAE,OAAQ,GAAG,CAAC,YAAoB,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,YAAoB,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;YAC9G,KAAK,EAAE,OAAQ,GAAG,CAAC,YAAoB,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,YAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;YACxG,SAAS,EAAE,OAAQ,GAAG,CAAC,YAAoB,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,YAAoB,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,SAAS;SAC3I;QACH,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC;IAC1B,MAAM,MAAM,GAAuB;QACjC,aAAa,EAAE,OAAO,GAAG,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;QACjG,YAAY,EAAE,OAAO,GAAG,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY;QAC7F,UAAU,EAAE,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU;QACrF,YAAY,EAAE,OAAO,GAAG,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY;QAC7F,UAAU,EAAE,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU;QACrF,WAAW,EAAE,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW;QACzF,cAAc,EAAE,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc;QACrG,SAAS;QACT,QAAQ;QACR,YAAY;QACZ,UAAU,EAAE,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;QAC3E,MAAM,EAAE,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;QAC/D,eAAe,EAAE,OAAO,GAAG,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI;KACvF,CAAC;IACF,MAAM,CAAC,IAAI,CAAC,yCAAyC,MAAM,CAAC,aAAa,iBAAiB,MAAM,CAAC,YAAY,eAAe,MAAM,CAAC,UAAU,iBAAiB,MAAM,CAAC,YAAY,eAAe,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IACrN,MAAM,CAAC,IAAI,CAAC,oCAAoC,MAAM,CAAC,SAAS,CAAC,KAAK,SAAS,MAAM,CAAC,SAAS,CAAC,UAAU,cAAc,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,YAAY,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;IACtM,MAAM,CAAC,IAAI,CAAC,mCAAmC,MAAM,CAAC,QAAQ,CAAC,KAAK,cAAc,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9G,MAAM,CAAC,IAAI,CAAC,yCAAyC,MAAM,CAAC,YAAY,CAAC,OAAO,cAAc,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC;IAC/H,MAAM,CAAC,IAAI,CAAC,2BAA2B,MAAM,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC,CAAC;IAClF,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
package/dist/src/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
  /* eslint-disable @typescript-eslint/no-explicit-any */
8
8
  // OpenClaw Plugin API 没有提供类型定义,需要使用 any
9
- import { parseConfig } from "./config.js";
9
+ import { parseConfig, shouldSkipRecallForSession } from "./config.js";
10
10
  import { RecallEngine } from "./recall.js";
11
11
  import { ProfileManager } from "./profile.js";
12
12
  import { VectorStore } from "./vector.js";
@@ -42,6 +42,9 @@ let serviceStarted = false;
42
42
  let serviceStarting = false;
43
43
  // ---- Auto-Settle 状态 ----
44
44
  let settleRunning = false; // 防止并发 settle
45
+ // ---- 月度晋升状态 ----
46
+ let monthlyPromotionCheckedDate = null; // 每月 1 号自动触发检查
47
+ let monthlyPromotionRunning = false;
45
48
  // ---- 每日兜底 Condense 状态 ----
46
49
  // 在 before_prompt_build 中检查:昨天是否有 session 文件但 short-term 为空/不存在
47
50
  // 如果是,说明昨天的对话没被 condense(/new 没触发),自动补全
@@ -155,13 +158,18 @@ const CONDENSE_SYSTEM_PROMPT = `你是一个对话记忆整理助手。请将原
155
158
 
156
159
  ## 输出格式规则
157
160
  每条记录一行,格式:
158
- \`[时段] 主题词 | 关键实体 | 一句话摘要\`
161
+ \`[时段] 主题词 | 关键实体 | 一句话摘要 #标签1 #标签2 #标签3\`
159
162
 
160
163
  ### 字段说明
161
164
  1. **[时段]**:从对话中提取的时间标签,如 [03-14 晚上]、[03-14 凌晨](保留原样,用于检索"昨晚"等)
162
165
  2. **主题词**:2-4个核心动词/名词,空格分隔(如:备份 iCloud 同步)
163
166
  3. **关键实体**:涉及的具体名称/数字(如:1.9GB、musetalk、300505.SZ)
164
167
  4. **一句话摘要**:完整描述事件(20字以内)
168
+ 5. **概念标签**:3-5个 #标签,空格分隔,每个标签2-4字。选择标准:
169
+ - 技术名词:项目名、工具名、框架名(如 #engram #OpenClaw #jiti)
170
+ - 实体类型:人名、地名、股票代码(如 #深圳 #06181)
171
+ - 行为分类:搬家、购物、调试、部署、作息等抽象概念
172
+ - 不要用"记忆"、"对话"、"用户"等泛化词作标签
165
173
 
166
174
  ## 处理规则
167
175
  1. **每个事件单独一行**:不同话题必须分开,只有完全相同主题的连续对话才能合并
@@ -181,9 +189,9 @@ Scott [03-13 下午]: 帮我拉新的分支,我需要解决context-notice__ico
181
189
  Shadow [03-13 下午]: 已创建分支 scotthuang/fix/dashboard-context-notice-icon-width 并提交修复
182
190
 
183
191
  输出:
184
- [03-13 下午] 模拟盘 持仓查询 | 06181 200股 675.0 650.0 -5000 -3.7% | 查看ScottK线账户持仓,小幅亏损
185
- [03-13 下午] OpenClaw 用户头像 自定义 | grouped-render.ts chat-avatar | 查看源码确认不支持用户自定义头像
186
- [03-13 下午] OpenClaw 修复 分支创建 | context-notice__icon width | 创建分支修复图标宽度bug
192
+ [03-13 下午] 模拟盘 持仓查询 | 06181 200股 675.0 650.0 -5000 -3.7% | 查看ScottK线账户持仓,小幅亏损 #港股 #06181 #模拟盘 #持仓
193
+ [03-13 下午] OpenClaw 用户头像 自定义 | grouped-render.ts chat-avatar | 查看源码确认不支持用户自定义头像 #OpenClaw #头像 #自定义 #前端
194
+ [03-13 下午] OpenClaw 修复 分支创建 | context-notice__icon width | 创建分支修复图标宽度bug #OpenClaw #bugfix #CSS #分支
187
195
 
188
196
  只输出整理后的内容,不要解释。`;
189
197
  /**
@@ -814,7 +822,7 @@ export default function register(api) {
814
822
  serviceStarting = false;
815
823
  }
816
824
  }
817
- logger.info(`[engram] before_prompt_build triggered, prompt length=${prompt.length}, messages=${Array.isArray(event.messages) ? event.messages.length : "N/A"}, sessionId=${ctx?.sessionId || "N/A"}, first200="${prompt.slice(0, 200)}"`);
825
+ logger.info(`[engram] before_prompt_build triggered, prompt length=${prompt.length}, messages=${Array.isArray(event.messages) ? event.messages.length : "N/A"}, sessionId=${ctx?.sessionId || "N/A"}, sessionKey=${ctx?.sessionKey || "N/A"}, first200="${prompt.slice(0, 200)}"`);
818
826
  if (prompt.length < 5)
819
827
  return;
820
828
  // 检查黑名单:系统引导消息不需要召回
@@ -822,6 +830,12 @@ export default function register(api) {
822
830
  logger.info(`[engram] Skipping recall for system startup prompt`);
823
831
  return;
824
832
  }
833
+ // 检查 session 级别跳过:cron/自动化任务不需要召回
834
+ const sessionKey = ctx?.sessionKey;
835
+ if (shouldSkipRecallForSession(sessionKey, config.skipRecall)) {
836
+ logger.info(`[engram] Skipping recall for session: "${sessionKey}" (matched skipRecall rule)`);
837
+ return;
838
+ }
825
839
  // ---- 每日兜底 Condense: 检查昨天是否有遗漏的对话 ----
826
840
  // 逻辑:今天第一次触发时,扫描昨天的 session 文件,
827
841
  // 如果 short-term/昨天.md 不存在或内容过少,自动 condense 补全
@@ -968,6 +982,43 @@ export default function register(api) {
968
982
  }
969
983
  })();
970
984
  }
985
+ // ---- 月度晋升:每月 1 号自动触发 6 维评分晋升 ----
986
+ // fire-and-forget,不阻塞当前对话
987
+ if (config.promotion.mode !== "off" && !monthlyPromotionRunning) {
988
+ const todayForPromotion = getLocalDateString();
989
+ if (todayForPromotion.endsWith("-01") && monthlyPromotionCheckedDate !== todayForPromotion) {
990
+ monthlyPromotionCheckedDate = todayForPromotion;
991
+ monthlyPromotionRunning = true;
992
+ (async () => {
993
+ try {
994
+ const llmCall = makeLlmCall(config);
995
+ if (!llmCall) {
996
+ logger.info(`[engram:monthly-promotion] No LLM config, skipping`);
997
+ return;
998
+ }
999
+ logger.info(`[engram:monthly-promotion] Triggering monthly promotion (mode=${config.promotion.mode})...`);
1000
+ const results = await runMonthlySettle({
1001
+ workspaceDir,
1002
+ config,
1003
+ llmCall,
1004
+ vectorStore: vectorStore
1005
+ ? (text, category, importance, triggers) => vectorStore.store(text, category, importance, triggers)
1006
+ : undefined,
1007
+ vectorPrune: vectorStore
1008
+ ? (threshold, maxPrune) => vectorStore.prune(threshold, maxPrune)
1009
+ : undefined,
1010
+ }, config.promotion.mode);
1011
+ logger.info(`[engram:monthly-promotion] Done: ${results.join(" | ")}`);
1012
+ }
1013
+ catch (err) {
1014
+ logger.error(`[engram:monthly-promotion] Failed: ${err}`);
1015
+ }
1016
+ finally {
1017
+ monthlyPromotionRunning = false;
1018
+ }
1019
+ })();
1020
+ }
1021
+ }
971
1022
  // ---- 纯图片消息检测:如果没有用户实际文字内容则跳过 recall ----
972
1023
  const hasMedia = prompt.includes("[media attached:");
973
1024
  // 去掉 [media attached: ...] 标记、系统图片指令、Conversation info 等元数据
@@ -1536,8 +1587,8 @@ export default function register(api) {
1536
1587
  });
1537
1588
  results.forEach(r => console.log(` ${r}`));
1538
1589
  });
1539
- mem.command("monthly-settle").description("Run monthly settle (selective vectorize + prune)").action(async () => {
1540
- console.log("Running monthly settlement...");
1590
+ mem.command("monthly-settle").description("Run monthly settle (6-dim promotion + prune)").action(async () => {
1591
+ console.log(`Running monthly settlement (promotion mode: ${config.promotion.mode})...`);
1541
1592
  if (vectorStore) {
1542
1593
  await vectorStore.startup();
1543
1594
  }
@@ -1547,7 +1598,7 @@ export default function register(api) {
1547
1598
  llmCall: makeLlmCall(config),
1548
1599
  vectorStore: vectorStore ? (text, category, importance, triggers) => vectorStore.store(text, category, importance, triggers) : undefined,
1549
1600
  vectorPrune: vectorStore ? (threshold, maxPrune) => vectorStore.prune(threshold, maxPrune) : undefined,
1550
- });
1601
+ }, config.promotion.mode);
1551
1602
  results.forEach(r => console.log(` ${r}`));
1552
1603
  });
1553
1604
  mem.command("profile").description("Show user profile").action(async () => {