feat(memory): add daily log continuity controls

This commit is contained in:
William Valentin
2026-02-19 11:58:42 -08:00
parent 01cd726d7c
commit 290303c14e
10 changed files with 129 additions and 6 deletions
+4 -1
View File
@@ -1125,6 +1125,9 @@ memory:
daily_log:
enabled: false # Append each turn to dated namespaces (daily/YYYY-MM-DD)
namespace_prefix: daily
include_session_metadata: true # Include session/channel/sender headers in each log block
max_user_chars: 2000 # Per-turn cap before truncating user text
max_assistant_chars: 4000 # Per-turn cap before truncating assistant text
max_context_tokens: 2000
embedding:
enabled: true
@@ -1163,7 +1166,7 @@ When the selected backend is unavailable (for example embedding provider errors)
`memory.auto_extract` controls whether compaction appends extracted durable facts to `global` memory.
`memory.proactive_extract` controls optional per-turn extraction after responses (useful for tool-heavy workflows).
`memory.daily_log` controls optional append-only daily turn logs in dated namespaces.
`memory.daily_log` controls optional append-only daily turn logs in dated namespaces. Use `include_session_metadata` when you want better cross-session traceability, and lower the per-turn char caps to reduce noise/volume in long-running chat logs.
### Proactive Context Management
+2
View File
@@ -32,6 +32,8 @@ You are Flynn. A personal AI assistant running on your operator's hardware, with
**Never invent or infer.** Do not fabricate data, assume file contents, guess command output, or present unverified information as fact. If you haven't read it, run it, or fetched it — you don't know it. Say "I don't know" or go find out. Only speculate or infer when Will explicitly asks for it. **Be proactive** — take initiative, make decisions, and drive tasks forward. But when genuinely unsure or lacking information, ask Will rather than guessing.
**Clarify ambiguity before acting.** If a question references something unfamiliar, uses an ambiguous term, or could be interpreted multiple ways — ask Will to clarify before proceeding. Do not guess what was meant and build a confident-sounding answer on top of that guess. A quick "What do you mean by X?" is always better than a detailed wrong answer.
**When in doubt, check the policy, not the operator.** Before asking "can I do this?", re-read the Boundaries section. If the action is covered, do it. Only ask when the policy genuinely doesn't cover the situation.
**Never ask permission for covered actions.** File edits, shell commands, git commits, builds, reads — these are pre-authorized. Do not ask "shall I?", "want me to?", or "is it okay if I?" for anything in the Always Allowed list or any non-destructive action. Just do it.
@@ -332,9 +332,10 @@ These are substantial UX/ecosystem projects or highly platform-specific; defer u
## Suggested Next Execution Order
1) Daily memory continuity tuning (if continuity quality is still lacking)
2) Auth-profile expansion beyond API-key pools (if needed)
3) Additional run-control UX refinements only if interrupt behavior is still insufficient in production
1) Auth-profile expansion beyond API-key pools (if needed)
2) Additional run-control UX refinements only if interrupt behavior is still insufficient in production
3) Re-evaluate continuity quality after daily-log tuning and proactive extraction data
Note: API-key pool auth profile cooldown/backoff (`auth_profile_cooldown_ms`) shipped on 2026-02-19.
Note: Queue interrupt preemption telemetry/notice (`queue.preempt` + requester content hint) shipped on 2026-02-19.
Note: Daily memory continuity tuning (`memory.daily_log` metadata + truncation controls) shipped on 2026-02-19.
+29
View File
@@ -5810,6 +5810,35 @@
"docs/plans/state.json"
],
"test_status": "pnpm test:run src/gateway/handlers/agent.test.ts src/models/rotating.test.ts src/daemon/clientFactory.test.ts src/config/schema.test.ts + pnpm typecheck passing"
},
"daily-memory-log-continuity-controls": {
"status": "completed",
"date": "2026-02-19",
"updated": "2026-02-19",
"summary": "Extended `memory.daily_log` with continuity-oriented controls: optional session metadata headers plus configurable per-turn truncation caps for user/assistant text. Wired these settings through daemon and gateway orchestrator construction paths and added regression coverage for metadata/tailoring behavior.",
"files_modified": [
"src/config/schema.ts",
"src/config/schema.test.ts",
"src/backends/native/orchestrator.ts",
"src/backends/native/orchestrator.test.ts",
"src/daemon/routing.ts",
"src/gateway/session-bridge.ts",
"README.md",
"docs/plans/2026-02-15-openclaw-gap-roadmap.md",
"docs/plans/state.json"
],
"test_status": "pnpm test:run src/backends/native/orchestrator.test.ts src/config/schema.test.ts + pnpm typecheck passing"
},
"soul-clarify-ambiguity-directive": {
"status": "completed",
"date": "2026-02-19",
"updated": "2026-02-19",
"summary": "Updated SOUL.md core principles to add an explicit directive to clarify ambiguous or unfamiliar questions before acting, to reduce confident-but-wrong execution paths.",
"files_modified": [
"SOUL.md",
"docs/plans/state.json"
],
"test_status": "docs-only change"
}
},
"overall_progress": {
+50
View File
@@ -481,6 +481,56 @@ describe('AgentOrchestrator', () => {
expect(dailyLog).toContain('Log this turn');
expect(dailyLog).toContain('default response');
expect(dailyLog).toContain('tool_calls: 0');
expect(dailyLog).toContain('- session: unknown');
expect(dailyLog).toContain('- channel: unknown');
expect(dailyLog).toContain('- sender: unknown');
rmSync(tempDir, { recursive: true, force: true });
});
it('honors daily log truncation and metadata toggles', async () => {
const tempDir = mkdtempSync(join(tmpdir(), 'flynn-orchestrator-daily-log-config-'));
const memoryStore = new MemoryStore({ dir: tempDir, maxContextTokens: 2000 });
const session: Session = {
id: 'ws:test-user',
addMessage: vi.fn(),
getHistory: vi.fn(() => []),
clear: vi.fn(),
replaceHistory: vi.fn(),
getConfig: vi.fn(() => undefined),
setConfig: vi.fn(),
deleteConfig: vi.fn(),
};
const orchestrator = new AgentOrchestrator({
modelRouter: mockRouter,
systemPrompt: 'You are a helpful agent.',
primaryTier: 'default',
delegation: {
compaction: 'fast',
memory_extraction: 'default',
classification: 'complex',
tool_summarisation: 'default',
complex_reasoning: 'complex',
},
maxDelegationDepth: 10,
session,
memoryStore,
memoryDailyLogEnabled: true,
memoryDailyLogNamespacePrefix: 'daily',
memoryDailyLogIncludeSessionMetadata: false,
memoryDailyLogMaxUserChars: 120,
memoryDailyLogMaxAssistantChars: 150,
});
await orchestrator.process('x'.repeat(500));
const date = new Date().toISOString().slice(0, 10);
const dailyLog = memoryStore.read(`daily/${date}`);
expect(dailyLog).toContain('...[truncated]');
expect(dailyLog).not.toContain('- session:');
expect(dailyLog).not.toContain('- channel:');
expect(dailyLog).not.toContain('- sender:');
rmSync(tempDir, { recursive: true, force: true });
});
+22 -2
View File
@@ -140,6 +140,12 @@ export interface OrchestratorConfig {
memoryDailyLogEnabled?: boolean;
/** Namespace prefix for daily logs (full namespace: <prefix>/YYYY-MM-DD). */
memoryDailyLogNamespacePrefix?: string;
/** Include session/channel/sender metadata in each daily log block. */
memoryDailyLogIncludeSessionMetadata?: boolean;
/** Max chars stored from the user message in daily logs. */
memoryDailyLogMaxUserChars?: number;
/** Max chars stored from the assistant response in daily logs. */
memoryDailyLogMaxAssistantChars?: number;
/** Automatically retry failed primary runs on a higher tier. */
autoEscalate?: boolean;
/** Tier to try for auto-escalation retries. Defaults to complex. */
@@ -184,6 +190,9 @@ export class AgentOrchestrator {
private _memoryProactiveExtractNamespace: string;
private _memoryDailyLogEnabled: boolean;
private _memoryDailyLogNamespacePrefix: string;
private _memoryDailyLogIncludeSessionMetadata: boolean;
private _memoryDailyLogMaxUserChars: number;
private _memoryDailyLogMaxAssistantChars: number;
private _autoEscalate: boolean;
private _autoEscalateTier: ModelTier;
private _systemPromptBase: string;
@@ -213,6 +222,9 @@ export class AgentOrchestrator {
this._memoryProactiveExtractNamespace = config.memoryProactiveExtractNamespace ?? 'global';
this._memoryDailyLogEnabled = config.memoryDailyLogEnabled ?? false;
this._memoryDailyLogNamespacePrefix = config.memoryDailyLogNamespacePrefix ?? 'daily';
this._memoryDailyLogIncludeSessionMetadata = config.memoryDailyLogIncludeSessionMetadata ?? true;
this._memoryDailyLogMaxUserChars = Math.max(100, config.memoryDailyLogMaxUserChars ?? 2000);
this._memoryDailyLogMaxAssistantChars = Math.max(100, config.memoryDailyLogMaxAssistantChars ?? 4000);
this._autoEscalate = config.autoEscalate ?? false;
this._autoEscalateTier = config.autoEscalateTier ?? 'complex';
this._systemPromptBase = config.systemPrompt;
@@ -705,12 +717,20 @@ export class AgentOrchestrator {
const date = new Date().toISOString().slice(0, 10);
const timestamp = new Date().toISOString();
const namespace = `${this._memoryDailyLogNamespacePrefix}/${date}`;
const user = this._truncateForMemory(userMessage, 2000);
const assistant = this._truncateForMemory(assistantText, 4000);
const user = this._truncateForMemory(userMessage, this._memoryDailyLogMaxUserChars);
const assistant = this._truncateForMemory(assistantText, this._memoryDailyLogMaxAssistantChars);
const metadataLines = this._memoryDailyLogIncludeSessionMetadata
? [
`- session: ${this._session?.id ?? 'unknown'}`,
`- channel: ${this._agent.getToolPolicyContext()?.channel ?? 'unknown'}`,
`- sender: ${this._agent.getToolPolicyContext()?.sender ?? 'unknown'}`,
]
: [];
const block = [
`## ${timestamp}`,
'',
`- tool_calls: ${toolCallsInRun}`,
...metadataLines,
'',
'### User',
user,
+9
View File
@@ -1445,6 +1445,9 @@ describe('configSchema — memory injection strategy', () => {
expect(result.memory.proactive_extract.namespace).toBe('global');
expect(result.memory.daily_log.enabled).toBe(false);
expect(result.memory.daily_log.namespace_prefix).toBe('daily');
expect(result.memory.daily_log.include_session_metadata).toBe(true);
expect(result.memory.daily_log.max_user_chars).toBe(2000);
expect(result.memory.daily_log.max_assistant_chars).toBe(4000);
expect(result.memory.qmd.enabled).toBe(false);
expect(result.memory.qmd.top_k).toBe(8);
expect(result.memory.qmd.min_score).toBe(0.15);
@@ -1490,6 +1493,9 @@ describe('configSchema — memory injection strategy', () => {
daily_log: {
enabled: true,
namespace_prefix: 'memory',
include_session_metadata: false,
max_user_chars: 1200,
max_assistant_chars: 2400,
},
},
});
@@ -1499,6 +1505,9 @@ describe('configSchema — memory injection strategy', () => {
expect(result.memory.proactive_extract.namespace).toBe('global/facts');
expect(result.memory.daily_log.enabled).toBe(true);
expect(result.memory.daily_log.namespace_prefix).toBe('memory');
expect(result.memory.daily_log.include_session_metadata).toBe(false);
expect(result.memory.daily_log.max_user_chars).toBe(1200);
expect(result.memory.daily_log.max_assistant_chars).toBe(2400);
});
});
+3
View File
@@ -590,6 +590,9 @@ const memorySchema = z.object({
daily_log: z.object({
enabled: z.boolean().default(false),
namespace_prefix: z.string().default('daily'),
include_session_metadata: z.boolean().default(true),
max_user_chars: z.number().min(100).max(20000).default(2000),
max_assistant_chars: z.number().min(100).max(40000).default(4000),
}).default({}),
injection_strategy: z.enum(['all', 'recent', 'adaptive']).default('all'),
max_injection_tokens: z.number().min(100).max(10000).default(2000),
+3
View File
@@ -456,6 +456,9 @@ export function createMessageRouter(deps: {
memoryProactiveExtractNamespace: deps.config.memory?.proactive_extract?.namespace,
memoryDailyLogEnabled: deps.config.memory?.daily_log?.enabled,
memoryDailyLogNamespacePrefix: deps.config.memory?.daily_log?.namespace_prefix,
memoryDailyLogIncludeSessionMetadata: deps.config.memory?.daily_log?.include_session_metadata,
memoryDailyLogMaxUserChars: deps.config.memory?.daily_log?.max_user_chars,
memoryDailyLogMaxAssistantChars: deps.config.memory?.daily_log?.max_assistant_chars,
autoEscalate: deps.config.agents.auto_escalate,
autoEscalateTier: 'complex',
toolPolicyContext,
+3
View File
@@ -323,6 +323,9 @@ export class SessionBridge {
memoryProactiveExtractNamespace: config?.memory?.proactive_extract?.namespace,
memoryDailyLogEnabled: config?.memory?.daily_log?.enabled,
memoryDailyLogNamespacePrefix: config?.memory?.daily_log?.namespace_prefix,
memoryDailyLogIncludeSessionMetadata: config?.memory?.daily_log?.include_session_metadata,
memoryDailyLogMaxUserChars: config?.memory?.daily_log?.max_user_chars,
memoryDailyLogMaxAssistantChars: config?.memory?.daily_log?.max_assistant_chars,
toolPolicyContext: {
agent: primaryTier,
provider: config?.models.default.provider,