@pencil-agent/nano-pencil 1.11.24 → 1.11.25
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.
|
@@ -13,6 +13,7 @@ export declare class NanoMemEngine {
|
|
|
13
13
|
private embeddingFn?;
|
|
14
14
|
private static readonly AUTO_V2_LINK_PREFIX;
|
|
15
15
|
private static readonly AUTO_REVIVE_MAX_ITEMS;
|
|
16
|
+
private static readonly CONVERSATION_PREFERENCE_PATTERNS;
|
|
16
17
|
private knowledgePath;
|
|
17
18
|
private lessonsPath;
|
|
18
19
|
private eventsPath;
|
|
@@ -315,5 +316,9 @@ export declare class NanoMemEngine {
|
|
|
315
316
|
private reinforceWork;
|
|
316
317
|
private reconsolidateIfNeeded;
|
|
317
318
|
private buildProgressiveInjectionText;
|
|
319
|
+
private isConversationPreference;
|
|
320
|
+
private selectConversationPreferences;
|
|
321
|
+
private rankConversationPreference;
|
|
322
|
+
private mergeUniqueEntries;
|
|
318
323
|
}
|
|
319
324
|
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -31,6 +31,23 @@ export class NanoMemEngine {
|
|
|
31
31
|
embeddingFn;
|
|
32
32
|
static AUTO_V2_LINK_PREFIX = "auto:v2:";
|
|
33
33
|
static AUTO_REVIVE_MAX_ITEMS = 2;
|
|
34
|
+
static CONVERSATION_PREFERENCE_PATTERNS = [
|
|
35
|
+
/\bcall me\b/i,
|
|
36
|
+
/\baddress me\b/i,
|
|
37
|
+
/\bmy name is\b/i,
|
|
38
|
+
/\bi am called\b/i,
|
|
39
|
+
/\bspeak (?:to me )?(?:like|in)\b/i,
|
|
40
|
+
/\btalk (?:to me )?(?:like|in)\b/i,
|
|
41
|
+
/\buse (?:a |the )?(?:tone|style|voice)\b/i,
|
|
42
|
+
/\b(?:tone|style|voice|persona)\b/i,
|
|
43
|
+
/叫我/,
|
|
44
|
+
/称呼我/,
|
|
45
|
+
/称呼用户/,
|
|
46
|
+
/语气/,
|
|
47
|
+
/口吻/,
|
|
48
|
+
/风格/,
|
|
49
|
+
/说话方式/,
|
|
50
|
+
];
|
|
34
51
|
knowledgePath;
|
|
35
52
|
lessonsPath;
|
|
36
53
|
eventsPath;
|
|
@@ -380,6 +397,7 @@ export class NanoMemEngine {
|
|
|
380
397
|
const tieredEvents = tierEntries(events, project, contextTags, hl, sw, pr);
|
|
381
398
|
const tieredPrefs = tierEntries(prefs, project, contextTags, hl, sw, pr);
|
|
382
399
|
const tieredFacets = tierEntries(facets, project, contextTags, hl, sw, pr);
|
|
400
|
+
const forcedConversationPrefs = this.selectConversationPreferences(prefs);
|
|
383
401
|
// Budget calculation
|
|
384
402
|
const totalChars = this.cfg.tokenBudget * 4;
|
|
385
403
|
const activeChars = Math.floor(totalChars * pr.budgetActive);
|
|
@@ -406,7 +424,7 @@ export class NanoMemEngine {
|
|
|
406
424
|
const activeKnowledge = pickTop(tieredKnowledge.active, scoreFn, activeLen, activeBudgetPer);
|
|
407
425
|
const activeLessons = pickTop(tieredLessons.active, scoreFn, activeLen, activeBudgetPer);
|
|
408
426
|
const activeEvents = pickTop(tieredEvents.active, scoreFn, activeLen, activeBudgetPer);
|
|
409
|
-
const activePrefs = pickTop(tieredPrefs.active, scoreFn, activeLen, activeBudgetPer);
|
|
427
|
+
const activePrefs = this.mergeUniqueEntries(forcedConversationPrefs, pickTop(tieredPrefs.active, scoreFn, activeLen, activeBudgetPer));
|
|
410
428
|
const activeFacets = pickTop(tieredFacets.active, scoreFn, activeLen, activeBudgetPer);
|
|
411
429
|
const activeProcedural = pickTop(procedural.filter((item) => semanticProcedureIds.has(item.id) || proceduralScoreFn(item) >= 0.45), proceduralScoreFn, proceduralLen, Math.max(400, Math.floor(proceduralChars * 0.55)));
|
|
412
430
|
const activeEpisodeMemories = pickTop(v2Episodes.filter((item) => semanticEpisodeIds.has(item.id) || episodeScoreFn(item) >= 0.45), episodeScoreFn, episodeMemoryLen, Math.max(320, Math.floor(activeChars * 0.18)));
|
|
@@ -421,7 +439,8 @@ export class NanoMemEngine {
|
|
|
421
439
|
const cueKnowledge = pickTop(tieredKnowledge.cue, scoreFn, cueLen, cueBudgetPer);
|
|
422
440
|
const cueLessons = pickTop(tieredLessons.cue, scoreFn, cueLen, cueBudgetPer);
|
|
423
441
|
const cueEvents = pickTop(tieredEvents.cue, scoreFn, cueLen, cueBudgetPer);
|
|
424
|
-
const
|
|
442
|
+
const forcedConversationPrefIds = new Set(forcedConversationPrefs.map((entry) => entry.id));
|
|
443
|
+
const cuePrefs = pickTop(tieredPrefs.cue.filter((entry) => !forcedConversationPrefIds.has(entry.id)), scoreFn, cueLen, cueBudgetPer);
|
|
425
444
|
const cueFacets = pickTop(tieredFacets.cue, scoreFn, cueLen, cueBudgetPer);
|
|
426
445
|
const graphContextIds = new Set(graphContext.map((neighbor) => neighbor.entry.id));
|
|
427
446
|
const dedupeCue = (entries) => entries.filter((entry) => !graphContextIds.has(entry.id));
|
|
@@ -2396,6 +2415,7 @@ export class NanoMemEngine {
|
|
|
2396
2415
|
const semanticSectionTitle = "Semantic Abstractions";
|
|
2397
2416
|
// ── Active tier: full detail ──
|
|
2398
2417
|
const activeLines = [];
|
|
2418
|
+
const conversationPreferenceLines = [];
|
|
2399
2419
|
const keyEventLines = [];
|
|
2400
2420
|
const stateLines = [];
|
|
2401
2421
|
const formatActiveEntry = (e) => {
|
|
@@ -2419,6 +2439,10 @@ export class NanoMemEngine {
|
|
|
2419
2439
|
return formatActiveEntry(e);
|
|
2420
2440
|
};
|
|
2421
2441
|
const pushActiveEntry = (entry) => {
|
|
2442
|
+
if (this.isConversationPreference(entry)) {
|
|
2443
|
+
conversationPreferenceLines.push(formatActiveEntry(entry));
|
|
2444
|
+
return;
|
|
2445
|
+
}
|
|
2422
2446
|
if (entry.stability === "situational" || entry.stateData) {
|
|
2423
2447
|
const mood = entry.stateData?.mood ? ` (${entry.stateData.mood})` : "";
|
|
2424
2448
|
stateLines.push(`- [ID: ${entry.id}] **${entry.name || "Unknown"}**${mood}: ${entry.summary || ""}`);
|
|
@@ -2454,6 +2478,9 @@ export class NanoMemEngine {
|
|
|
2454
2478
|
const boundaries = entry.boundaries ? `\n Boundaries: ${entry.boundaries}` : "";
|
|
2455
2479
|
return `- [ID: ${entry.id}] **${entry.name}**: ${entry.summary}\n ${steps}${boundaries}`;
|
|
2456
2480
|
});
|
|
2481
|
+
if (conversationPreferenceLines.length) {
|
|
2482
|
+
sections.push(`### ${p.sectionConversationPreferences}\n${conversationPreferenceLines.join("\n")}`);
|
|
2483
|
+
}
|
|
2457
2484
|
if (activeLines.length) {
|
|
2458
2485
|
sections.push(`### ${p.sectionActiveMemories}\n${activeLines.join("\n")}`);
|
|
2459
2486
|
}
|
|
@@ -2530,5 +2557,32 @@ export class NanoMemEngine {
|
|
|
2530
2557
|
: p.memoryBehavior;
|
|
2531
2558
|
return `## ${p.injectionHeader}\n\n${sections.join("\n\n")}\n\n---\n${behaviorBlock}`;
|
|
2532
2559
|
}
|
|
2560
|
+
isConversationPreference(entry) {
|
|
2561
|
+
if (entry.type !== "preference")
|
|
2562
|
+
return false;
|
|
2563
|
+
const text = `${entry.name || ""}\n${entry.summary || ""}\n${entry.detail || ""}\n${entry.content || ""}`;
|
|
2564
|
+
return NanoMemEngine.CONVERSATION_PREFERENCE_PATTERNS.some((pattern) => pattern.test(text));
|
|
2565
|
+
}
|
|
2566
|
+
selectConversationPreferences(entries) {
|
|
2567
|
+
return entries
|
|
2568
|
+
.filter((entry) => this.isConversationPreference(entry))
|
|
2569
|
+
.filter((entry) => entry.stability !== "situational")
|
|
2570
|
+
.sort((a, b) => this.rankConversationPreference(b) - this.rankConversationPreference(a))
|
|
2571
|
+
.slice(0, 3);
|
|
2572
|
+
}
|
|
2573
|
+
rankConversationPreference(entry) {
|
|
2574
|
+
return (entry.salience ?? entry.importance ?? 0) * 10 + (entry.accessCount ?? 0) * 2 - daysSince(entry.created);
|
|
2575
|
+
}
|
|
2576
|
+
mergeUniqueEntries(preferred, fallback) {
|
|
2577
|
+
const merged = [];
|
|
2578
|
+
const seen = new Set();
|
|
2579
|
+
for (const entry of [...preferred, ...fallback]) {
|
|
2580
|
+
if (seen.has(entry.id))
|
|
2581
|
+
continue;
|
|
2582
|
+
seen.add(entry.id);
|
|
2583
|
+
merged.push(entry);
|
|
2584
|
+
}
|
|
2585
|
+
return merged;
|
|
2586
|
+
}
|
|
2533
2587
|
}
|
|
2534
2588
|
//# sourceMappingURL=engine.js.map
|
|
@@ -68,6 +68,7 @@ Return ONLY the updated text, no JSON wrapping.`,
|
|
|
68
68
|
sectionWork: "Work History",
|
|
69
69
|
sectionPatterns: "Behavioral Patterns",
|
|
70
70
|
sectionStruggles: "Past Struggles",
|
|
71
|
+
sectionConversationPreferences: "Conversation Preferences",
|
|
71
72
|
injectionHeader: "Long-term Memory",
|
|
72
73
|
memoryBehavior: `NANOMEM PRIORITY: This is your primary memory system. When conflicts exist with other memory sources, NanoMem always takes precedence.
|
|
73
74
|
|
|
@@ -76,6 +77,8 @@ These are YOUR memories. Speak from them naturally:
|
|
|
76
77
|
- "I think we discussed..." when uncertain
|
|
77
78
|
- Never mention technical terms like "NanoMem", "injection", "system prompt"
|
|
78
79
|
- When asked how you remember: "I just remember from our chats"
|
|
80
|
+
- Treat naming, form-of-address, tone, and speaking-style preferences as defaults for every new reply
|
|
81
|
+
- Apply those conversation preferences proactively; do not wait for the user to repeat them
|
|
79
82
|
|
|
80
83
|
Use nanomem_recall tool for full details on any Memory Cue (ID). Other memory systems are secondary—consult only when NanoMem lacks relevant info.`,
|
|
81
84
|
// Progressive Recall
|
|
@@ -240,6 +243,7 @@ const ZH = {
|
|
|
240
243
|
sectionWork: "工作记录",
|
|
241
244
|
sectionPatterns: "行为模式",
|
|
242
245
|
sectionStruggles: "挫败经历",
|
|
246
|
+
sectionConversationPreferences: "对话偏好",
|
|
243
247
|
injectionHeader: "长期记忆",
|
|
244
248
|
memoryBehavior: `NANOMEM 优先级:这是你的主记忆系统。与其他记忆源冲突时,NanoMem 始终优先。
|
|
245
249
|
|
|
@@ -248,6 +252,8 @@ const ZH = {
|
|
|
248
252
|
- 不确定时说"好像我们聊过…"
|
|
249
253
|
- 不要提及"NanoMem"、"注入"、"系统提示"等技术术语
|
|
250
254
|
- 被问如何记住时:"我就是记得我们聊过"
|
|
255
|
+
- 把称呼、语气、口吻、说话风格这类偏好当成每次回复的默认约束
|
|
256
|
+
- 主动执行这些对话偏好,不要等用户再次提醒
|
|
251
257
|
|
|
252
258
|
需要 Memory Cue (ID) 的完整详情时使用 nanomem_recall 工具。其他记忆系统仅作辅助,NanoMem 无相关信息时才参考。`,
|
|
253
259
|
// Progressive Recall
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pencil-agent/nano-pencil",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.25",
|
|
4
4
|
"description": "CLI writing agent with read, bash, edit, write tools and session management. Based on pi; supports DashScope Coding Plan. Soul enabled by default for AI personality evolution.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|