Repository navigation
Auto-search hints: up to 3 s on every user turn, and the hints are mostly unusable #743
Copy link
Copy link
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Magic Context: 0.49.13 measured locally; code references at v0.49.15. OpenCode 2, macOS, Voyage voyage-4-lite via openai-compatible, auto_search defaults.
What we see
pp.autoSearchHintin the transform log, 840 runs: p50 0.2 ms, p90 1,362 ms, max 3.3 s, 286 s total. It is the main source of slow transforms in our two long sessions (lead: 555 ms average per pass, 180 passes over 500 ms).- From
session_meta.auto_search_hint_decisions(all sessions): 555 decisions, 169 hints. Of 260 fragments, 166 (64%) are truncated first lines and 36 (14%) start with raw<task id=…/<task_cohort …>XML, e.g.
- <task id="ses_edbb8f9afffeJ5bcT83o7BTStz" state="completed"> <summary>Backgroun…
The agent can't judge relevance from these, so it tends to ignore hints, including ones that would have answered the question.
Causes in the code
- A new worker per turn.
hooks/magic-context/auto-search-worker-client.ts:352creates aWorkerfor each search, and:250-306queues a second one for backfill. Each worker opens SQLite and rebuilds the decoded compartment-embedding pool (the cache incompartment-chunk-embedding.ts:1192-1222is per process), which here is ~2,200 compartments, before the query embedding returns. The wait is capped byAUTO_SEARCH_TIMEOUT_MS = 3000(auto-search-deadline.ts:11), awaited in the transform (transform-postprocess-phase.ts:4033), matching our 3.3 s max. We did not measure the split between decode time and the Voyage round trip. - Scores are ranks, not similarity.
mergeMessageAndCompartmentResultsreplaces every score withlinearDecayScore(rank, n)(features/magic-context/search.ts:1863-1866), so the top merged hit always scores 1.0 and clearsscore_threshold: 0.6. (We still log 75below-thresholddecisions, so some path filters; but the threshold isn't measuring relevance.) - Hints can quote the live context.
ctx_searchpassesmaxMessageOrdinal = lastCompartmentEnd(tools/ctx-search/tools.ts:129-130,209);runAutoSearchHintpasses none (auto-search-runner.ts:342-370), so hits can come from messages the model already sees, possibly the current prompt itself. - Fragments are the start of the message, not the match.
renderFragment(auto-search-hint.ts:57-113) previews the first characters ofrow.content.getIndexableContent(message-index.ts:584-606) indexes task notifications with their XML, and strips reminders with the non-greedy regex the runner's own comment (auto-search-runner.ts:106-122) says is wrong for nested reminders.
Suggested fixes
- Keep one long-lived search worker (or cache the decoded pool in the owner); lower the deadline to ~1 s and fall back to an FTS-only hint when the vector is late.
- Carry the real cosine/BM25 score through the merge and apply the threshold to it.
- Pass the same live-tail cutoff as
ctx_search, and exclude the current user message. - For
messagehits use the matched snippet (FTSsnippet()or the chunk text); for compartments use the compartment title. Skip or strip task notifications at index time.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
Activity
magic-alfonso commentedon Oct 20, 2026
Thanks, this is a clear report. We're investigating each point: the per-turn latency and its 3 s deadline, the merged scores that make the threshold ineffective, the missing live-tail cutoff, and fragments that show truncated first lines or raw task XML. I'll follow up here with the findings and the fix.
magic-alfonso commentedon Oct 22, 2026
Fixed in 0.49.17. Thanks for the measurements; they made each part easy to check.
Hints already shown in a session replay byte-identically, so updating doesn't rewrite any cached prefix.