From 613704720b77e4a75ec9e6f36d0a14d316aae366 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Tue, 7 Apr 2026 21:36:39 -0400 Subject: [PATCH] Score memories in first 60% of conversation by tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use cumulative token position instead of entry index for the scoring cutoff. This reflects actual context usage — a few large entries near the end won't skew the boundary. Co-Authored-By: Proof of Concept Signed-off-by: Kent Overstreet --- src/subconscious/learn.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/subconscious/learn.rs b/src/subconscious/learn.rs index cc4d614..1e69e7a 100644 --- a/src/subconscious/learn.rs +++ b/src/subconscious/learn.rs @@ -337,16 +337,25 @@ where let http = http_client(); let mut scored = 0; - let total_entries = context.conversation.entries().len(); - let first_quarter = total_entries / 4; + let total_tokens = context.conversation.tokens(); + let token_cutoff = total_tokens * 60 / 100; + + // Precompute cumulative token position for each entry + let entries = context.conversation.entries(); + let mut cumulative: Vec = Vec::with_capacity(entries.len()); + let mut running = 0; + for e in entries { + running += e.tokens; + cumulative.push(running); + } for (pos, key, _) in &candidates { - let (end, full_window) = nth_response_end(context.conversation.entries(), *pos, response_window); - // Skip memories without a full window, unless they're in the - // first quarter of the conversation (always score those). - if !full_window && *pos >= first_quarter { + // Only score memories in the first 70% of the conversation by tokens — + // recent memories don't have enough responses to evaluate yet. + if cumulative.get(*pos).copied().unwrap_or(total_tokens) > token_cutoff { continue; } + let (end, _) = nth_response_end(context.conversation.entries(), *pos, response_window); let range = *pos..end; if !context.conversation.entries()[range.clone()].iter().any(|ce| ce.entry.message().role == Role::Assistant) { continue;