Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/architecture/agent-memory-test-seams/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Agent Memory Test Seams Plan

## Implementation Approach

- Add a small test-local helper in `memoryPresenter.test.ts` that exposes service-level runtime
states through `getMutableRuntimeStateForTests()`.
- Replace facade-level runtime casts with helper calls against `embedding`, `vectorStore`,
`maintenance`, `reflection`, `persona`, and `workingMemory`.
- Replace facade wrapper calls with direct service calls:
- `embedding.warmEmbeddingConnection(...)`
- `vectorStore.clearReady(...)`
- Delete the `MemoryPresenter` private compat accessor method, private runtime getters, and private
wrapper methods.

## Compatibility

No production behavior, persisted data, public route DTO, IPC contract, or memory runtime behavior
changes. The only intended contract change is test-only: facade private runtime shims are no longer
available.

## Test Strategy

- Run `memoryPresenter.test.ts` to verify the moved seams preserve existing coverage.
- Run node typecheck to catch private-member cast type drift.
- Run format, i18n, lint, and diff whitespace checks before handoff.
32 changes: 32 additions & 0 deletions docs/architecture/agent-memory-test-seams/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Agent Memory Test Seams Spec

## User Need

Agent memory tests should keep their lifecycle and race coverage without forcing `MemoryPresenter`
to retain facade-level private accessors that exist only for tests.

## Goal

Remove the legacy `MemoryPresenter` runtime accessor shims and migrate affected tests to the
existing service-level `getMutableRuntimeStateForTests()` seams.

## Acceptance Criteria

- `MemoryPresenter` no longer contains `retainRuntimeCompatAccessorsForTests()` or private runtime
getter wrappers.
- `memoryPresenter.test.ts` no longer casts the presenter facade to read `vectorStoreReady`,
`embeddingDrains`, `personaLocks`, or related compat getters.
- Existing lifecycle, cleanup, cold-path, cooldown, and dispose tests remain present and pass.
- Production memory behavior and public APIs are unchanged.

## Constraints

- Do not create a GitHub issue, branch, or commit.
- Keep this as a local refactor; do not rewrite tests into broader behavior-only harnesses.
- Preserve the existing service-level test seams for this change.

## Non-Goals

- Do not address native SQLite environment setup.
- Do not remove valuable lifecycle tests.
- Do not broaden memory service APIs or export new production types only for tests.
7 changes: 7 additions & 0 deletions docs/architecture/agent-memory-test-seams/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Agent Memory Test Seams Tasks

- [x] Create local architecture SDD artifacts without GitHub issue sync.
- [x] Add service-level runtime helper to `memoryPresenter.test.ts`.
- [x] Migrate facade runtime accessor probes to service-level seams.
- [x] Remove `MemoryPresenter` facade test shims.
- [x] Run targeted tests and validation commands through `mise exec -- pnpm ...`.
102 changes: 1 addition & 101 deletions src/main/presenter/memoryPresenter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
type MemoryInjectionResult,
type MemoryRuntimePort
} from './injection'
import { isSafeAgentId, type AgentMemoryRow, type IMemoryVectorStore } from './types'
import { isSafeAgentId, type AgentMemoryRow } from './types'
import type {
MemoryCandidate,
MemoryConflictPair,
Expand Down Expand Up @@ -165,31 +165,6 @@ export class MemoryPresenter implements MemoryRuntimePort {
triggerEmbedding: (agentId) => this.embedding.processPendingEmbeddings(agentId),
clearConsolidationCooldown: (agentId) => this.maintenance.clearCooldown(agentId)
})

this.retainRuntimeCompatAccessorsForTests()
}

// Legacy facade-oracle tests intentionally probe these private runtime accessors via casts.
// Keep this method until those tests move to explicit service-level test helpers.
private retainRuntimeCompatAccessorsForTests(): void {
void this.vectorStoreReady
void this.vectorStores
void this.vectorStoreIdentities
void this.vectorStoreLocks
void this.vectorStoreWarmups
void this.vectorStoreDimensionFailures
void this.embeddingWarmups
void this.embeddingDrains
void this.reindexing
void this.backfilling
void this.consolidationTimers
void this.lastConsolidationAt
void this.reflectionAttemptWatermark
void this.personaAttemptWatermark
void this.personaLocks
void this.workingRefreshInFlight
void this.warmEmbeddingConnection
void this.clearVectorStoreReady
}

startBackgroundMaintenance(): void {
Expand All @@ -204,81 +179,6 @@ export class MemoryPresenter implements MemoryRuntimePort {
this.maintenance.warmActiveAgents()
}

private get vectorStoreReady(): Map<string, string> {
return this.vectorStore.getMutableRuntimeStateForTests().vectorStoreReady
}

private get vectorStores(): Map<string, Promise<IMemoryVectorStore>> {
return this.vectorStore.getMutableRuntimeStateForTests().vectorStores
}

private get vectorStoreIdentities(): Map<string, string> {
return this.vectorStore.getMutableRuntimeStateForTests().vectorStoreIdentities
}

private get vectorStoreLocks(): Map<string, Promise<unknown>> {
return this.vectorStore.getMutableRuntimeStateForTests().vectorStoreLocks
}

private get vectorStoreWarmups(): Map<string, Promise<void>> {
return this.embedding.getMutableRuntimeStateForTests().vectorStoreWarmups
}

private get vectorStoreDimensionFailures(): Map<string, number> {
return this.embedding.getMutableRuntimeStateForTests().vectorStoreDimensionFailures
}

private get embeddingWarmups(): Map<string, Promise<void>> {
return this.embedding.getMutableRuntimeStateForTests().embeddingWarmups
}

private get embeddingDrains(): Map<string, Promise<unknown>> {
return this.embedding.getMutableRuntimeStateForTests().embeddingDrains
}

private get reindexing(): Map<string, Promise<void>> {
return this.embedding.getMutableRuntimeStateForTests().reindexing
}

private get backfilling(): Map<string, Promise<void>> {
return this.embedding.getMutableRuntimeStateForTests().backfilling
}

private get consolidationTimers(): Map<string, NodeJS.Timeout> {
return this.maintenance.getMutableRuntimeStateForTests().consolidationTimers
}

private get lastConsolidationAt(): Map<string, number> {
return this.maintenance.getMutableRuntimeStateForTests().lastConsolidationAt
}

private get reflectionAttemptWatermark(): Map<string, number> {
return this.reflection.getMutableRuntimeStateForTests().reflectionAttemptWatermark
}

private get personaAttemptWatermark(): Map<string, number> {
return this.persona.getMutableRuntimeStateForTests().personaAttemptWatermark
}

private get personaLocks(): Map<string, Promise<unknown>> {
return this.persona.getMutableRuntimeStateForTests().personaLocks
}

private get workingRefreshInFlight(): Set<string> {
return this.workingMemory.getMutableRuntimeStateForTests().workingRefreshInFlight
}

private warmEmbeddingConnection(
agentId: string,
embedding: { providerId: string; modelId: string }
): void {
this.embedding.warmEmbeddingConnection(agentId, embedding)
}

private clearVectorStoreReady(agentId: string): void {
this.vectorStore.clearReady(agentId)
}

isEnabled(agentId: string): boolean {
return this.runtime.isEnabled(agentId)
}
Expand Down
Loading