Skip to content

fix: flush memory persistence on channel shutdown for short-lived conversations#401

Open
l33t0 wants to merge 2 commits intospacedriveapp:mainfrom
l33t0:fix/adapter-memory-persistence
Open

fix: flush memory persistence on channel shutdown for short-lived conversations#401
l33t0 wants to merge 2 commits intospacedriveapp:mainfrom
l33t0:fix/adapter-memory-persistence

Conversation

@l33t0
Copy link
Contributor

@l33t0 l33t0 commented Mar 11, 2026

Summary

Short-lived conversations on Discord and Telegram were losing their context because memory persistence only triggers every N messages (default: 50). Conversations that ended before reaching the threshold never got their context saved to agent memory.

The root cause is NOT adapter-specific - all adapters share the same channel code path. The issue is that the periodic trigger is the only mechanism, and there was no flush on channel close.

  • Added force_memory_persistence() that spawns a memory persistence branch unconditionally (bypassing the message_interval threshold)
  • Called on channel shutdown when there are unsaved messages (message_count > 0)
  • Still respects the memory_persistence.enabled config flag
  • The periodic interval-based trigger continues to work as before for long-running conversations

Also fixes a pre-existing clippy collapsible_if lint in the Signal adapter code.

Closes #363

Test plan

  • cargo clippy --all-targets -- -D warnings passes clean
  • All 586 lib tests pass
  • Start a short Discord/Telegram conversation (< 50 messages), wait for channel idle timeout, verify memory persistence branch spawns in logs
  • Verify long webchat sessions still trigger periodic persistence at the interval

Note

Key Changes: Adds channel shutdown hook that flushes memory persistence for short-lived conversations. The force_memory_persistence() method spawns a memory persistence branch unconditionally on channel close if there are unsaved messages. Also refactors nested conditionals in Signal adapter code using let-guards for improved readability and Clippy compliance.

Written by Tembo for commit d490b4a. This will update automatically on new commits.

Short-lived conversations (common on Discord and Telegram) that never
reach the message_interval threshold (default: 50 messages) would
lose their context entirely because memory persistence only triggered
at the interval boundary.

Adds force_memory_persistence() which spawns a memory persistence
branch unconditionally when a channel stops, ensuring any unsaved
conversation context is committed regardless of message count.

Also fixes pre-existing clippy collapsible_if lint in signal adapter.

Closes spacedriveapp#363
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 71fbfd18-37a0-42ab-86d0-7dfb8d170430

📥 Commits

Reviewing files that changed from the base of the PR and between d490b4a and c2008c1.

📒 Files selected for processing (1)
  • src/agent/channel.rs

Walkthrough

Adds unconditional memory persistence on channel shutdown to persist unsaved conversation context, and refactors Signal adapter shorthand handling in message routing using a Rust let-guard to streamline control flow without changing behavior.

Changes

Cohort / File(s) Summary
Memory persistence & tests
src/agent/channel.rs
Adds a private async force_memory_persistence method and invokes it during channel shutdown to unconditionally spawn memory-persistence branches (when enabled) after flushing coalesce buffer; resets message_count and records branch IDs. Adds tests for memory persistence config default, disabled, and zero-interval gating.
Message routing refactor
src/tools/send_message_to_another_channel.rs
Replaces nested conditional with a let-guard that binds parsed Signal target when target.adapter == "signal" and current_adapter starts with signal:, consolidating adapter assignment and broadcast logic while preserving prior behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding memory persistence flush on channel shutdown to prevent loss of context in short-lived conversations.
Description check ✅ Passed The description clearly explains the problem, solution, and impact, relating directly to the code changes in channel.rs and Signal adapter refactoring.
Linked Issues check ✅ Passed The PR directly addresses issue #363 by implementing memory persistence flush on channel shutdown, ensuring short-lived conversations persist context and closing the architectural gap in Discord/Telegram adapters.
Out of Scope Changes check ✅ Passed All changes are scoped to the stated objectives: force_memory_persistence() implementation in channel.rs and Signal adapter refactoring for Clippy compliance.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/agent/channel.rs (1)

1024-1030: Add a shutdown regression for below-threshold persistence.

This fix only runs in teardown, but the tests in this module still exercise event routing rather than channel shutdown. A focused test around message_count > 0 and memory_persistence.enabled would keep this from regressing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agent/channel.rs` around lines 1024 - 1030, Teardown now persists unsaved
context only when self.message_count > 0 by calling
self.force_memory_persistence(), but there is no targeted test to prevent
regressions; add a focused unit test for the Channel (or agent) shutdown path
that sets memory_persistence.enabled=true, sets message_count to a value > 0,
invokes the channel shutdown/teardown sequence, and asserts that
force_memory_persistence() (or the underlying persistence side-effect) was
called; additionally add a complementary test with message_count == 0 to ensure
no persistence occurs, and wire the test to observe the actual persistence
effect (mock the memory persistence component or inspect persisted state) rather
than relying on event routing tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/agent/channel.rs`:
- Around line 1024-1030: Teardown now persists unsaved context only when
self.message_count > 0 by calling self.force_memory_persistence(), but there is
no targeted test to prevent regressions; add a focused unit test for the Channel
(or agent) shutdown path that sets memory_persistence.enabled=true, sets
message_count to a value > 0, invokes the channel shutdown/teardown sequence,
and asserts that force_memory_persistence() (or the underlying persistence
side-effect) was called; additionally add a complementary test with
message_count == 0 to ensure no persistence occurs, and wire the test to observe
the actual persistence effect (mock the memory persistence component or inspect
persisted state) rather than relying on event routing tests.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c32f8451-020d-436b-a759-1b5bd7f804c8

📥 Commits

Reviewing files that changed from the base of the PR and between 0a97964 and d490b4a.

📒 Files selected for processing (2)
  • src/agent/channel.rs
  • src/tools/send_message_to_another_channel.rs

Comment on lines +3089 to +3093
self.message_count = 0;

match spawn_memory_persistence_branch(&self.state, &self.deps).await {
Ok(branch_id) => {
self.memory_persistence_branches.insert(branch_id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If spawn_memory_persistence_branch fails, clearing message_count here drops the signal that there was unsaved context. Consider only zeroing the counter after a successful spawn.

Suggested change
self.message_count = 0;
match spawn_memory_persistence_branch(&self.state, &self.deps).await {
Ok(branch_id) => {
self.memory_persistence_branches.insert(branch_id);
match spawn_memory_persistence_branch(&self.state, &self.deps).await {
Ok(branch_id) => {
self.message_count = 0;
self.memory_persistence_branches.insert(branch_id);

}

#[test]
fn memory_persistence_config_defaults_to_enabled() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These new tests are only asserting config fields (or even just config.enabled) and don’t exercise the shutdown flush behavior added above. I’d either drop them (to avoid a false sense of coverage) or replace with a regression that drives the channel shutdown path and asserts a memory-persistence branch is spawned when message_count > 0 and memory_persistence.enabled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Universal Memory Gap: Discord & Telegram conversations not committed to the agent's memory

1 participant