From 8c826e581cbb3c92856dc4b0839a613519e82573 Mon Sep 17 00:00:00 2001 From: xj Date: Wed, 18 Feb 2026 03:38:48 -0800 Subject: [PATCH] fix(channel): store raw user message and skip memory recall with history MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two fixes for conversation history quality: 1. Store raw msg.content in ConversationHistoryMap instead of enriched_message — memory context is ephemeral per-request and pollutes future turns when persisted. 2. Skip memory recall when conversation history exists — prior turns already provide context. Memory recall adds noise and can mislead the model (e.g. old 'seen' entries overshadowing a code variable named seen in the current conversation). --- src/channels/mod.rs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/channels/mod.rs b/src/channels/mod.rs index b9ec121..c5c989e 100644 --- a/src/channels/mod.rs +++ b/src/channels/mod.rs @@ -1111,10 +1111,6 @@ async fn process_channel_message( return; } }; - - let memory_context = - build_memory_context(ctx.memory.as_ref(), &msg.content, ctx.min_relevance_score).await; - if ctx.auto_save_memory && msg.content.chars().count() >= AUTOSAVE_MIN_MESSAGE_CHARS { let autosave_key = conversation_memory_key(&msg); let _ = ctx @@ -1128,15 +1124,16 @@ async fn process_channel_message( .await; } - let enriched_message = if memory_context.is_empty() { - msg.content.clone() - } else { - format!("{memory_context}{}", msg.content) - }; - println!(" ⏳ Processing message..."); let started_at = Instant::now(); + let had_prior_history = ctx + .conversation_histories + .lock() + .unwrap_or_else(|e| e.into_inner()) + .get(&history_key) + .is_some_and(|turns| !turns.is_empty()); + // Preserve user turn before the LLM call so interrupted requests keep context. append_sender_turn(ctx.as_ref(), &history_key, ChatMessage::user(&msg.content)); @@ -1149,11 +1146,16 @@ async fn process_channel_message( .cloned() .unwrap_or_default(); let mut prior_turns = normalize_cached_channel_turns(prior_turns_raw); - // Keep persisted history clean (raw user text), but inject memory context - // for the current provider call by enriching the newest user turn only. - if let Some(last_turn) = prior_turns.last_mut() { - if last_turn.role == "user" { - last_turn.content = enriched_message.clone(); + + // Only enrich with memory context when there is no prior conversation + // history. Follow-up turns already include context from previous messages. + if !had_prior_history { + let memory_context = + build_memory_context(ctx.memory.as_ref(), &msg.content, ctx.min_relevance_score).await; + if let Some(last_turn) = prior_turns.last_mut() { + if last_turn.role == "user" && !memory_context.is_empty() { + last_turn.content = format!("{memory_context}{}", msg.content); + } } }