@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.
- package/dist/src/__tests__/promotion-dryrun.d.ts +6 -0
- package/dist/src/__tests__/promotion-dryrun.js +105 -0
- package/dist/src/__tests__/promotion-dryrun.js.map +1 -0
- package/dist/src/config.d.ts +21 -0
- package/dist/src/config.js +71 -0
- package/dist/src/config.js.map +1 -1
- package/dist/src/index.js +60 -9
- package/dist/src/index.js.map +1 -1
- package/dist/src/promotion.d.ts +52 -0
- package/dist/src/promotion.js +140 -0
- package/dist/src/promotion.js.map +1 -0
- package/dist/src/recall.d.ts +24 -7
- package/dist/src/recall.js +126 -15
- package/dist/src/recall.js.map +1 -1
- package/dist/src/settle.d.ts +4 -5
- package/dist/src/settle.js +74 -28
- package/dist/src/settle.js.map +1 -1
- package/package.json +1 -1
|
@@ -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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"}
|
package/dist/src/config.d.ts
CHANGED
|
@@ -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;
|
package/dist/src/config.js
CHANGED
|
@@ -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
|
}
|
package/dist/src/config.js.map
CHANGED
|
@@ -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;
|
|
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 (
|
|
1540
|
-
console.log(
|
|
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 () => {
|