Skip to content

feat(memory): add turn-based distillation trigger alongside idle timeout #442

Description

@Aaronontheweb

Problem

The SessionMemoryObserverActor only triggers memory distillation on ReceiveTimeout — 90 seconds of complete silence. For busy sessions with long tool loops (10+ minutes of continuous activity), memories don't form until the session goes fully idle. This makes memory formation very slow for active sessions and painful during testing.

Current behavior

  1. Observer accumulates transcript lines as SendUserMessage, SessionOutput, etc. arrive
  2. Sets _hasNewContent = true when substantive content is received
  3. Waits for ReceiveTimeout (default 90s of no messages) to trigger distillation
  4. No other trigger path exists (the DistillMemories explicit request is wired but not sent during passivation)

A session doing a 25-iteration tool loop at 30s/call runs for ~12 minutes with no distillation. Memories only form after the user stops talking and 90 seconds pass.

Proposed change

Add a turn-based trigger that distills every N completed turns, regardless of idle state. For example, after every 3 TurnCompleted events, trigger distillation of the accumulated transcript.

Tradeoffs to consider

Waiting longer (current approach):

  • More context available → potentially higher-quality distillation (more connections, better dedup)
  • Fewer LLM distillation calls → lower cost
  • Natural batching of related turns

Distilling more frequently (proposed):

  • Memories form during active sessions, not just after
  • Smaller transcripts per distillation → faster/cheaper per call, but more calls total
  • Risk of fragmented memories that a single larger distillation would have merged
  • Better for testing and interactive feedback loops

Suggested approach

  • Make the turn interval configurable: MemoryObserverDistillEveryNTurns (default 3-5)
  • Keep the idle timeout as a fallback for partial-turn content
  • The turn-based trigger and idle trigger should both check _hasNewContent to avoid empty distillations

Relevant code

  • src/Netclaw.Actors/Sessions/SessionMemoryObserverActor.cs — observer logic, TriggerDistillation(), ReceiveTimeout handler
  • src/Netclaw.Configuration/SessionConfig.csMemoryObserverIdleSeconds (default 90)

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    memoryMemory formation, recall, curation pipeline

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions