memory-neo4j: implement mid-session core memory refresh

Add `coreMemory.refreshAtContextPercent` config option to re-inject
core memories when context usage exceeds a threshold. This counters
the "lost in the middle" phenomenon documented by Liu et al. (2023).

Implementation:
- Extend before_agent_start hook event with context usage info
- Pass contextWindowTokens and estimatedUsedTokens to hooks
- Track mid-session refresh per session to prevent over-refreshing
- Clear refresh tracking on compaction
- Add comprehensive tests

Based on research: Liu et al., "Lost in the Middle: How Language
Models Use Long Contexts" (Stanford, 2023)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Tarun Sukhani
2026-02-04 18:00:32 +00:00
parent 007daf3c27
commit 1e4ffdcec8
5 changed files with 214 additions and 2 deletions

View File

@@ -31,6 +31,8 @@ import {
listChannelSupportedActions,
resolveChannelMessageToolHints,
} from "../../channel-tools.js";
import { estimateMessagesTokens } from "../../compaction.js";
import { DEFAULT_CONTEXT_TOKENS } from "../../defaults.js";
import { resolveOpenClawDocsPath } from "../../docs-path.js";
import { isTimeoutError } from "../../failover-error.js";
import { resolveModelAuthMode } from "../../model-auth.js";
@@ -850,10 +852,16 @@ export async function runEmbeddedAttempt(
let effectivePrompt = params.prompt;
if (hookRunner?.hasHooks("before_agent_start")) {
try {
// Calculate context usage for mid-session memory refresh
const contextWindowTokens = params.model.contextWindow ?? DEFAULT_CONTEXT_TOKENS;
const estimatedUsedTokens = estimateMessagesTokens(activeSession.messages);
const hookResult = await hookRunner.runBeforeAgentStart(
{
prompt: params.prompt,
messages: activeSession.messages,
contextWindowTokens,
estimatedUsedTokens,
},
{
agentId: hookAgentId,

View File

@@ -343,6 +343,10 @@ export type PluginHookBootstrapResult = {
export type PluginHookBeforeAgentStartEvent = {
prompt: string;
messages?: unknown[];
/** Model's total context window in tokens. */
contextWindowTokens?: number;
/** Estimated tokens currently used in context. */
estimatedUsedTokens?: number;
};
export type PluginHookBeforeAgentStartResult = {