[Enhancement]: Memory candidate retrieval searches the full noisy session context instead of the focused query — relevant facts fall out of the top-N the judge can pick from
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 19.9k
- Forks
- 2.3k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 30
Description
Summary
In process_context (crates/jcode-base/src/memory_agent.rs) the candidate set
is retrieved with the full relevance context:
let context = memory::format_context_for_relevance(&messages);
...
let context_embedding = ...; // embedding of `context`
...
let candidates = memory_manager.find_similar_hybrid(
&context,
&context_embedding,
memory::EMBEDDING_MAX_HITS,
)?;
A focused query (format_focused_query_for_relevance / focus_query_text) is
already built in the same function, but it is used only for the LLM rerank
step (rerank_candidates_consensus_attributed(&sidecar, &focused_query, ...)).
The full context includes <system-reminder> boilerplate, tool calls, tool
results and tool-error text, which dilutes the query embedding. Combined with a
small EMBEDDING_MAX_HITS (currently 10), the fact the task actually needs can be
ranked outside the pool the judge is even allowed to see, so no amount of judge
precision can recover it.
Impact
Users ask "how do I make X retrieve fact Y" and the answer is: it cannot, because
Y was never in the top-10. Concretely, in an ACP task asking about a Gitea access
token env var, the token fact was ranked below workflow/environment facts (the
noisy context was lexically closer to those), the judge never saw it, and the
agent answered incorrectly. This also silently defeats the whole two-stage design:
a good reranker over a bad candidate pool is bounded by the pool.
Root cause
process_context builds focused_query (line ~518) but retrieves candidates with
&context, &context_embedding (line ~657). The focused-query transform exists
precisely because the same function's benchmark notes that retrieval and reranking
degrade on long, noisy inputs:
/// Unlike [`format_context_for_relevance`], which concatenates up to a dozen
/// role-prefixed messages (including tool output) into one blob, this produces a
/// tighter query centered on the user's *current intent*. Memory retrieval and
/// (especially) cross-encoder reranking degrade badly on long, noisy inputs:
/// embeddings get diluted ...
Proposed change (implemented and verified locally)
Embed the focused query and retrieve candidates with it, falling back to the full
context only when the focused query is empty or identical to the context:
let (query_text, query_embedding) = if focused_query.trim().is_empty()
|| focused_query == context
{
(context.clone(), context_embedding.clone())
} else {
let q = focused_query.clone();
let q_emb = match tokio::task::spawn_blocking(move || {
crate::embedding_backend::embed_query_active(&q)
})
.await
{
Ok(Ok((emb, _model))) => emb,
_ => context_embedding.clone(),
};
(focused_query.clone(), q_emb)
};
let candidates = memory_manager.find_similar_hybrid(
&query_text,
&query_embedding,
memory::EMBEDDING_MAX_HITS,
)?;
Additionally, raise EMBEDDING_MAX_HITS (crates/jcode-base/src/memory.rs) from
10 to 30 so the judge sees a wider, more recall-complete pool before reranking:
/// Maximum embedding hits to verify with sidecar
pub const EMBEDDING_MAX_HITS: usize = 30;
Environment
- jcode v0.68.0, Linux x86_64, DeepSeek provider, local all-MiniLM-L6-v2 embeddings.
- ACP protocolVersion 1, host: Multica daemon.
- Verified locally: with focused-query retrieval + pool 30, the token fact entered
the judge's pool and was injected on the relevant turn.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in crates/jcode-base/src/memory_agent.rs, especially process_context, and trace how focused_query and context_embedding reach find_similar_hybrid. Check crates/jcode-base/src/memory.rs for EMBEDDING_MAX_HITS, then verify that focused-query retrieval falls back for empty or identical queries, uses a pool of 30, and admits the relevant fact in the described ACP scenario.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- ai
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100