agenr 0.9.18 → 0.9.19
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 +8 -0
- package/dist/openclaw-plugin/index.js +76 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.19 (2026-02-28)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
- OpenClaw plugin: store nudging - injects a system nudge when the
|
|
7
|
+
agent has not called agenr_store in 8+ turns (configurable via
|
|
8
|
+
storeNudge plugin config). Nudges are spaced by the threshold
|
|
9
|
+
interval, capped at 3 per session. (#290)
|
|
10
|
+
|
|
3
11
|
## 0.9.18 (2026-02-28)
|
|
4
12
|
|
|
5
13
|
### Features
|
|
@@ -659,7 +659,9 @@ function getMidSessionState(key) {
|
|
|
659
659
|
recentMessages: new RecentMessagesBuffer(),
|
|
660
660
|
lastRecallQuery: null,
|
|
661
661
|
recalledIds: /* @__PURE__ */ new Set(),
|
|
662
|
-
turnCount: 0
|
|
662
|
+
turnCount: 0,
|
|
663
|
+
lastStoreTurn: 0,
|
|
664
|
+
nudgeCount: 0
|
|
663
665
|
};
|
|
664
666
|
}
|
|
665
667
|
const existing = midSessionStates.get(normalizedKey);
|
|
@@ -670,11 +672,20 @@ function getMidSessionState(key) {
|
|
|
670
672
|
recentMessages: new RecentMessagesBuffer(),
|
|
671
673
|
lastRecallQuery: null,
|
|
672
674
|
recalledIds: /* @__PURE__ */ new Set(),
|
|
673
|
-
turnCount: 0
|
|
675
|
+
turnCount: 0,
|
|
676
|
+
lastStoreTurn: 0,
|
|
677
|
+
nudgeCount: 0
|
|
674
678
|
};
|
|
675
679
|
midSessionStates.set(normalizedKey, nextState);
|
|
676
680
|
return nextState;
|
|
677
681
|
}
|
|
682
|
+
function markStoreCall(key) {
|
|
683
|
+
if (typeof key !== "string" || key.trim().length === 0) {
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
const state = getMidSessionState(key);
|
|
687
|
+
state.lastStoreTurn = state.turnCount;
|
|
688
|
+
}
|
|
678
689
|
function clearMidSessionStates() {
|
|
679
690
|
midSessionStates.clear();
|
|
680
691
|
}
|
|
@@ -1630,7 +1641,10 @@ var MAX_RECALLED_SESSIONS = 200;
|
|
|
1630
1641
|
var DEFAULT_MID_SESSION_NORMAL_LIMIT = 5;
|
|
1631
1642
|
var DEFAULT_MID_SESSION_COMPLEX_LIMIT = 8;
|
|
1632
1643
|
var DEFAULT_MID_SESSION_QUERY_SIMILARITY_THRESHOLD = 0.85;
|
|
1644
|
+
var DEFAULT_STORE_NUDGE_THRESHOLD = 8;
|
|
1645
|
+
var DEFAULT_STORE_NUDGE_MAX_PER_SESSION = 3;
|
|
1633
1646
|
var sessionRecalledEntries = /* @__PURE__ */ new Map();
|
|
1647
|
+
var sessionRef = { current: "" };
|
|
1634
1648
|
function isDebugEnabled(config) {
|
|
1635
1649
|
return process.env.AGENR_DEBUG === "1" || config?.debug === true;
|
|
1636
1650
|
}
|
|
@@ -1711,6 +1725,19 @@ function resolveMidSessionSimilarityThreshold(raw) {
|
|
|
1711
1725
|
}
|
|
1712
1726
|
return raw;
|
|
1713
1727
|
}
|
|
1728
|
+
function resolveStoreNudgeConfig(config) {
|
|
1729
|
+
return {
|
|
1730
|
+
enabled: config?.storeNudge?.enabled !== false,
|
|
1731
|
+
threshold: resolveMidSessionLimit(
|
|
1732
|
+
config?.storeNudge?.threshold,
|
|
1733
|
+
DEFAULT_STORE_NUDGE_THRESHOLD
|
|
1734
|
+
),
|
|
1735
|
+
maxPerSession: resolveMidSessionLimit(
|
|
1736
|
+
config?.storeNudge?.maxPerSession,
|
|
1737
|
+
DEFAULT_STORE_NUDGE_MAX_PER_SESSION
|
|
1738
|
+
)
|
|
1739
|
+
};
|
|
1740
|
+
}
|
|
1714
1741
|
function getRecallEntryId(item) {
|
|
1715
1742
|
if (typeof item !== "object" || item === null) {
|
|
1716
1743
|
return null;
|
|
@@ -2499,6 +2526,7 @@ var testingApi = {
|
|
|
2499
2526
|
clearMidSessionStates();
|
|
2500
2527
|
handoffSeenSessionIds.clear();
|
|
2501
2528
|
sessionRecalledEntries.clear();
|
|
2529
|
+
sessionRef.current = "";
|
|
2502
2530
|
},
|
|
2503
2531
|
readSessionsJson,
|
|
2504
2532
|
readAndParseSessionJsonl,
|
|
@@ -2530,6 +2558,7 @@ var plugin = {
|
|
|
2530
2558
|
"before_prompt_build",
|
|
2531
2559
|
async (event, ctx) => {
|
|
2532
2560
|
try {
|
|
2561
|
+
sessionRef.current = "";
|
|
2533
2562
|
const sessionKey = ctx.sessionKey ?? "";
|
|
2534
2563
|
if (!sessionKey) {
|
|
2535
2564
|
return;
|
|
@@ -2541,12 +2570,18 @@ var plugin = {
|
|
|
2541
2570
|
return;
|
|
2542
2571
|
}
|
|
2543
2572
|
const dedupeKey = ctx.sessionId ?? sessionKey;
|
|
2573
|
+
sessionRef.current = dedupeKey || sessionKey;
|
|
2544
2574
|
const agenrPath = resolveAgenrPath(config);
|
|
2545
2575
|
const budget = resolveBudget(config);
|
|
2546
2576
|
const project = config?.project?.trim() || void 0;
|
|
2547
2577
|
let markdown;
|
|
2548
2578
|
let midSessionMarkdown;
|
|
2549
2579
|
const isFirstInSession = dedupeKey ? !hasSeenSession(dedupeKey) : true;
|
|
2580
|
+
const stateKey = dedupeKey || sessionKey;
|
|
2581
|
+
const state = isFirstInSession ? void 0 : getMidSessionState(stateKey);
|
|
2582
|
+
if (state) {
|
|
2583
|
+
state.turnCount += 1;
|
|
2584
|
+
}
|
|
2550
2585
|
if (isFirstInSession) {
|
|
2551
2586
|
debugLog(debug, "session-start", `sessionKey=${sessionKey} dedupeKey=${dedupeKey} isFirst=true`);
|
|
2552
2587
|
if (dedupeKey) {
|
|
@@ -2702,10 +2737,7 @@ ${formatted.trim()}`);
|
|
|
2702
2737
|
} else {
|
|
2703
2738
|
debugLog(debug, "prompt-build", `sessionKey=${sessionKey} isFirst=false`);
|
|
2704
2739
|
}
|
|
2705
|
-
if (
|
|
2706
|
-
const stateKey = dedupeKey || sessionKey;
|
|
2707
|
-
const state = getMidSessionState(stateKey);
|
|
2708
|
-
state.turnCount += 1;
|
|
2740
|
+
if (state && config?.midSessionRecall?.enabled !== false) {
|
|
2709
2741
|
const rawPrompt = typeof event.prompt === "string" ? stripPromptMetadata(event.prompt) : "";
|
|
2710
2742
|
const userMessage = rawPrompt.trim();
|
|
2711
2743
|
if (userMessage) {
|
|
@@ -2783,23 +2815,46 @@ ${formatted.trim()}`);
|
|
|
2783
2815
|
const db = await ensurePluginDb(config);
|
|
2784
2816
|
const candidateSignal = await checkSignals(db, sessionKey, signalConfig);
|
|
2785
2817
|
debugLog(debug, "signals", `check result=${candidateSignal ? "found" : "none"}`);
|
|
2786
|
-
const
|
|
2787
|
-
const isCooldown = signalConfig.cooldownMs > 0 && Date.now() -
|
|
2788
|
-
const isMaxReached = signalConfig.maxPerSession > 0 &&
|
|
2818
|
+
const state2 = sessionSignalState.get(sessionKey) ?? { lastSignalAt: 0, signalCount: 0 };
|
|
2819
|
+
const isCooldown = signalConfig.cooldownMs > 0 && Date.now() - state2.lastSignalAt < signalConfig.cooldownMs;
|
|
2820
|
+
const isMaxReached = signalConfig.maxPerSession > 0 && state2.signalCount >= signalConfig.maxPerSession;
|
|
2789
2821
|
if (candidateSignal && !isCooldown && !isMaxReached) {
|
|
2790
2822
|
sessionSignalState.set(sessionKey, {
|
|
2791
2823
|
lastSignalAt: Date.now(),
|
|
2792
|
-
signalCount:
|
|
2824
|
+
signalCount: state2.signalCount + 1
|
|
2793
2825
|
});
|
|
2794
2826
|
signal = candidateSignal;
|
|
2795
2827
|
}
|
|
2796
2828
|
debugLog(debug, "signals", `cooldown=${isCooldown} maxReached=${isMaxReached} injected=${!!signal}`);
|
|
2797
2829
|
}
|
|
2798
|
-
|
|
2830
|
+
let storeNudge;
|
|
2831
|
+
if (!isFirstInSession && state) {
|
|
2832
|
+
const nudgeConfig = resolveStoreNudgeConfig(config);
|
|
2833
|
+
if (nudgeConfig.enabled) {
|
|
2834
|
+
const gap = state.turnCount - state.lastStoreTurn;
|
|
2835
|
+
debugLog(
|
|
2836
|
+
debug,
|
|
2837
|
+
"store-nudge",
|
|
2838
|
+
`check gap=${gap} threshold=${nudgeConfig.threshold} nudgeCount=${state.nudgeCount} maxPerSession=${nudgeConfig.maxPerSession}`
|
|
2839
|
+
);
|
|
2840
|
+
if (gap >= nudgeConfig.threshold && state.nudgeCount < nudgeConfig.maxPerSession) {
|
|
2841
|
+
storeNudge = "[MEMORY CHECK] You have not stored any knowledge recently. Review the conversation for decisions, preferences, lessons, or facts worth remembering.";
|
|
2842
|
+
state.nudgeCount += 1;
|
|
2843
|
+
state.lastStoreTurn = state.turnCount;
|
|
2844
|
+
debugLog(debug, "store-nudge", `injecting nudge #${state.nudgeCount}`);
|
|
2845
|
+
} else {
|
|
2846
|
+
const reason = gap < nudgeConfig.threshold ? "gap_below_threshold" : "max_reached";
|
|
2847
|
+
debugLog(debug, "store-nudge", `skipped reason=${reason}`);
|
|
2848
|
+
}
|
|
2849
|
+
} else {
|
|
2850
|
+
debugLog(debug, "store-nudge", "skipped reason=disabled");
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
const prependContext = [markdown, midSessionMarkdown, signal, storeNudge].filter(Boolean).join("\n\n");
|
|
2799
2854
|
debugLog(
|
|
2800
2855
|
debug,
|
|
2801
2856
|
"prompt-build",
|
|
2802
|
-
`prependContext total chars=${prependContext.length} (recall=${markdown?.length ?? 0} midSession=${midSessionMarkdown?.length ?? 0} signal=${signal?.length ?? 0})`
|
|
2857
|
+
`prependContext total chars=${prependContext.length} (recall=${markdown?.length ?? 0} midSession=${midSessionMarkdown?.length ?? 0} signal=${signal?.length ?? 0} nudge=${storeNudge?.length ?? 0})`
|
|
2803
2858
|
);
|
|
2804
2859
|
if (!prependContext) {
|
|
2805
2860
|
return;
|
|
@@ -2914,6 +2969,10 @@ ${formatted.trim()}`);
|
|
|
2914
2969
|
if (resetKey) {
|
|
2915
2970
|
clearMidSessionState(resetKey);
|
|
2916
2971
|
}
|
|
2972
|
+
const resetSessionId = event.context?.sessionEntry?.sessionId?.trim() ?? "";
|
|
2973
|
+
if (resetSessionId && resetSessionId !== resetKey) {
|
|
2974
|
+
clearMidSessionState(resetSessionId);
|
|
2975
|
+
}
|
|
2917
2976
|
}
|
|
2918
2977
|
const sessionKey = event.sessionKey;
|
|
2919
2978
|
if (!sessionKey) {
|
|
@@ -3069,6 +3128,11 @@ ${formatted.trim()}`);
|
|
|
3069
3128
|
if (runtimeConfig?.enabled === false) {
|
|
3070
3129
|
return makeDisabledToolResult();
|
|
3071
3130
|
}
|
|
3131
|
+
const key = sessionRef.current;
|
|
3132
|
+
if (key) {
|
|
3133
|
+
markStoreCall(key);
|
|
3134
|
+
debugLog(debug, "store-nudge", `store detected session=${key}`);
|
|
3135
|
+
}
|
|
3072
3136
|
const agenrPath = resolveAgenrPath(runtimeConfig);
|
|
3073
3137
|
const defaultProject = runtimeConfig?.project?.trim() || void 0;
|
|
3074
3138
|
const toolConfig = {
|