fix(memory): wire auto_extract through orchestrator compaction

This commit is contained in:
William Valentin
2026-02-15 22:18:55 -08:00
parent 2eccd3e8eb
commit a525ec7b2d
8 changed files with 79 additions and 0 deletions
+5
View File
@@ -93,6 +93,8 @@ export interface OrchestratorConfig {
contextWindow?: number;
/** Optional memory store for injecting persistent memory into the system prompt. */
memoryStore?: MemoryStore;
/** Enable/disable automatic memory extraction during compaction. */
memoryAutoExtract?: boolean;
/** Strategy for memory prompt injection. */
memoryInjectionStrategy?: 'all' | 'recent' | 'adaptive';
/** Maximum tokens allowed for injected memory context. */
@@ -124,6 +126,7 @@ export class AgentOrchestrator {
private _modelName?: string;
private _contextWindow?: number;
private _memoryStore?: MemoryStore;
private _memoryAutoExtract: boolean;
private _memoryInjectionStrategy: 'all' | 'recent' | 'adaptive';
private _memoryMaxInjectionTokens: number;
private _systemPromptBase: string;
@@ -139,6 +142,7 @@ export class AgentOrchestrator {
this._modelName = config.modelName;
this._contextWindow = config.contextWindow;
this._memoryStore = config.memoryStore;
this._memoryAutoExtract = config.memoryAutoExtract ?? true;
this._memoryInjectionStrategy = config.memoryInjectionStrategy ?? 'all';
this._memoryMaxInjectionTokens = config.memoryMaxInjectionTokens ?? 2000;
this._systemPromptBase = config.systemPrompt;
@@ -290,6 +294,7 @@ export class AgentOrchestrator {
orchestrator: this,
config,
memoryStore: this._memoryStore,
autoExtract: this._memoryAutoExtract,
});
// If nothing was actually compacted, skip the replace
+48
View File
@@ -3,6 +3,7 @@ import { compactHistory, DEFAULT_COMPACTION_CONFIG } from './compaction.js';
import type { CompactionConfig } from './compaction.js';
import type { AgentOrchestrator } from '../backends/native/orchestrator.js';
import type { Message } from '../models/types.js';
import type { MemoryStore } from '../memory/store.js';
function makeMockOrchestrator(summaryText = 'Summary of conversation'): AgentOrchestrator {
return {
@@ -146,4 +147,51 @@ describe('compactHistory', () => {
expect(result.messages.some(msg => typeof msg.content === 'string' && msg.content.includes('[Summary of earlier conversation]'))).toBe(true);
expect(result.messages.length).toBeGreaterThan(5);
});
it('auto-extracts memory facts by default when memoryStore is provided', async () => {
const messages = makeMessages(10);
const memoryStore = {
write: vi.fn(),
} as unknown as MemoryStore;
const orchestrator = {
getDelegationTier: vi.fn().mockReturnValue('fast'),
delegate: vi
.fn()
.mockResolvedValueOnce({
content: 'Compacted summary',
usage: { inputTokens: 100, outputTokens: 50 },
tier: 'fast',
})
.mockResolvedValueOnce({
content: '- User prefers concise answers.',
usage: { inputTokens: 40, outputTokens: 20 },
tier: 'fast',
}),
} as unknown as AgentOrchestrator;
await compactHistory({ messages, orchestrator, config, memoryStore });
expect(orchestrator.getDelegationTier).toHaveBeenCalledWith('memory_extraction');
expect(memoryStore.write).toHaveBeenCalledWith('global', '- User prefers concise answers.', 'append');
});
it('skips auto-extraction when autoExtract is false', async () => {
const messages = makeMessages(10);
const memoryStore = {
write: vi.fn(),
} as unknown as MemoryStore;
const orchestrator = {
getDelegationTier: vi.fn().mockReturnValue('fast'),
delegate: vi.fn().mockResolvedValue({
content: 'Compacted summary',
usage: { inputTokens: 100, outputTokens: 50 },
tier: 'fast',
}),
} as unknown as AgentOrchestrator;
await compactHistory({ messages, orchestrator, config, memoryStore, autoExtract: false });
expect(orchestrator.getDelegationTier).not.toHaveBeenCalledWith('memory_extraction');
expect(memoryStore.write).not.toHaveBeenCalled();
});
});
+1
View File
@@ -218,6 +218,7 @@ export function createMessageRouter(deps: {
modelName: effectiveModelName,
contextWindow: effectiveContextWindow,
memoryStore: deps.memoryStore,
memoryAutoExtract: deps.config.memory?.auto_extract,
memoryInjectionStrategy: deps.config.memory?.injection_strategy,
memoryMaxInjectionTokens: deps.config.memory?.max_injection_tokens,
toolPolicyContext: {
+1
View File
@@ -213,6 +213,7 @@ export class SessionBridge {
modelName: config?.models.default.model,
contextWindow: config?.models.default.context_window,
memoryStore: this.config.memoryStore,
memoryAutoExtract: config?.memory?.auto_extract,
memoryInjectionStrategy: config?.memory?.injection_strategy,
memoryMaxInjectionTokens: config?.memory?.max_injection_tokens,
toolPolicyContext: {