Repository navigation
Feat/hermes memory semantic recall - #101
Merged
CahidArda merged 6 commits intoNov 9, 2026
Merged
Conversation
…d WAITINDEXING checks
… past 1000 results, recover in wait_indexing
Memory text is always a HYBRID field and recall always merges $smart and $ann with $rrf. Remove the UPSTASH_HERMES_SEMANTIC flag, `semantic=` arguments, TEXT index support and the migrate command. An index from 0.2.x is refused with an error that says to run SEARCH.DROP; documents are kept and indexed again. Automatic recall injects 3 memories. Failed hybrid queries still fall back to keyword search for that call.
CahidArda
approved these changes
Nov 9, 2026
6 of 8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Upstash Redis Search now has
HYBRIDfields and the$ann/$rrfretrievers. This PR lets the Hermes memory provider use them for recall, behind a flag. Nothing changes without it.Why
Keyword recall (
$smart) only finds a memory that shares words with the message. On 12 paraphrased questions against 12 facts (throwaway database, synthetic data), the right memory was among the 3 recalled for 3 of 12 with keyword search and 11 of 12 with hybrid search on the first attempt (12 of 12 when a server-side failure was retried; see below). Same results with upstash-redis 1.8.x and 1.9.0.What changes (with
UPSTASH_HERMES_SEMANTIC=1/AgentMemory(semantic=True))text HYBRID. Only the memory text changes: chat transcripts stayTEXT, because aHYBRIDfield gets one embedding for its whole value.$rrfover{$smart}and{$ann}, both with the full user/kind filter. If a hybrid query errors, recall falls back to keyword for that call. Records carryretrieval: "hybrid" | "keyword".min_scoreapplies only to keyword results, because RRF scores are not on the same scale.$annhas no threshold, and its similarity scores (about 0.55 to 0.77 for related and unrelated text alike) did not support a cutoff.python -m upstash_hermes_memory.migrate --to hybrid|keyword, run with clients stopped. It reads credentials from the environment only (catalog rule 11).<ns>:migrate:baseline: counts plus a sample of memory keys.DESCRIBEafterwards, then recreates it, retrying and reconciling ambiguousCREATE,DESCRIBEandWAITINDEXINGsteps.--to <previous>against the original baseline. The check pages withinLIMIT1,000 andOFFSET10,000.--to keywordis the rollback, needed before reinstalling 0.2.x, whoseEXISTSOKcreate fails on a HYBRID index.UpstashErrorandhttpx.HTTPErroronly. Programming errors propagate.SearchIndex.ensure()now requiresWAITINDEXING == 1and checks the resolved index name.Also fixed
SearchIndex.querychecked for a missing index withSEARCH.COUNTon the query itself. That is invalid for retriever queries, because Search rejects$annin COUNT. It now counts{}.agentkitindex matches a TSSharedIndexSchema. It doesn't exist: the TS SDK createsagentkit_memory/agentkit_chat. The README already said so; the comments now agree.Found while testing (server side, for the Search team)
$annintermittently fails withERR dot metric only accepts unit-length vectors, got length 0.9994862. The same query failed 3 of 4 times, with or without a filter, and$rrfcontaining it fails too. That hit 2 to 3 of every 12 to 15 hybrid queries in the eval. The fallback covers it, but those calls lose semantic recall.$annreturns every document, so equal-weight RRF often ranks a keyword-only match first. In the eval, the right memory was in the top 3 every time but first only 3 of 12 times. Retriever weights could help; I left them at the default pending real data.Follow-up proposed
httpx.Client(timeout=None)for every command, which predates this PR. A stalled request can outlive Hermes's 8 s prefetch wait. Bounding it needs an upstash-redis timeout option, or reaching into the client's private internals, so it's a separate change.Not in this PR
TEXT).Tests
DESCRIBE. They cover command shapes, the accepted-schema and alias checks,WAITINDEXING == 0, fallback on server and transport errors, a failed fallback, the COUNT probe and provider wiring. On the migration side: pending updates, a failed drop, a failed create then resume, a count change, sample loss, rollback of an interrupted migration, stores past one 1,000-result page, andwait_indexingrecovery.test_semantic_redis.py: new index, meaning recall, user and chat isolation, empty store, and a migration round trip ending in a 0.2.2-style create.uv lock --lockedare clean.