Repository navigation
fix(hermes-memory): append chat turns in place instead of rewriting the transcript - #98
Merged
Merged
Conversation
…he transcript sync_turn read the whole chat document and wrote it back every turn (messages plus their extracted search text, about twice the transcript), so a long-running session sent more on every turn and would stop saving past Upstash's 10 MB request limit. ChatHistory.append_messages adds the turn with one atomic Lua script (JSON.ARRAPPEND / JSON.STRAPPEND, allow-key-locking) and leaves the document exactly as a full save would; the provider now reads and rewrites the transcript only for /undo, and no longer caches it in memory. Also fixes the /undo timestamp cut for resumed sessions: RedisJSON returns a whole-number stamp like 1000.0 as an int, which made the cut fall back to matching by content. Bumps upstash-hermes-memory to 0.2.2.
With the in-memory transcript cache gone, a write that failed (and was swallowed) was lost for good: a failed first turn left the chat starting at turn 2, and a failed write right after /undo cleared the undo flag, so the undone turn stayed in Redis and the post-undo turn was lost. Pending changes (turns to add, undo cuts) are now kept per session in order and cleared only after a successful write; normal turns still append only what is new.
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.
Fixes point 1 of Sertug's DX-3182 feedback, ahead of the catalog PR.
Problem
sync_turn→save_chatread the whole chat document (JSON.GET) and wrote it back (JSON.SET) on every turn: all messages plus the extracteduserMessages/modelMessagestext, about 2x the transcript. One long-running session (Sertug's Bot Chat: ~0.9 MB of text after 3 weeks) sends ~1.7 MB per turn and would stop saving silently once it passes Upstash's 10 MB request limit.Fix
ChatHistory.append_messages(session_id, messages, user_id=...): one atomic Lua script (#!lua flags=allow-key-locking, one key) thatJSON.ARRAPPENDs the messages,JSON.STRAPPENDs the new text to both search fields (with the\nseparator only when the field already has text), and setsupdatedAt. Text is JSON-encoded in Python (dumps, likeJSON.stringify), never by cjson. It returns 0 and writes nothing when the chat doesn't exist, so the provider falls back to a fullsave_chatfor the first turn./undo. The in-memory transcript cache is gone (it only served/undo, and grew with the session).ChatHistory. The TSsaveChatstill does a full replace; matching it there is a separate change.Also fixed:
/undoafter a restartRedisJSON returns a whole-number stamp like
1000.0as1000(verified live)._cut_by_timeonly acceptedfloat, so a transcript read back from Redis fell back to the content cut, and of two identical turns the wrong one could be removed. The in-memory cache used to hide this within one process. Any number now counts.Bumps
upstash-hermes-memoryto 0.2.2. Merging publishes it to PyPI.Tests
/, a whitespace-only message,partsmessages, a side's first text);createdAt/titlekept; search finds the appended text; append to a missing chat writes nothing.EVALwith only the new messages (noJSON.GET/JSON.SET), even with a 5 KB earlier turn./undowith stamps read back as ints.uv run pytest: 72 passed against live Redis. ruff, prettier,sync-version --check,uv sync --lockedclean.Not run: the Hermes e2e (
e2e/hermes_e2e.py, needs a real Hermes and a model key).