Repository navigation
Conversation
Move every call to the namespace-first v5 API via supermemory>=5,<6 (client.add / search / profile / memories.forget). Tools, config keys and env vars are unchanged; the existing sanitized container tag is the v5 namespace, so stored memories stay addressable. - capture still appends by stable document id (POST, not PATCH) with sm_source metadata; SDK retries stay off so one hook sends a batch once - search sends the pre-v5 threshold/rerank/rewrite explicitly (v5 lowered the default threshold to 0.3); "documents" maps to "chunks" - hits whose text is in chunk/chunks are rendered instead of blank - v5 profile has no query: profile + search run concurrently within api_timeout, keeping whichever leg succeeds - forget by id requires the API to confirm that exact id; forget by query searches memories only - refuse other SDK majors with a clear status message - add offline tests against the real SDK over a mock HTTP transport Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Contributor
|
Thank you @bbamnesia for this migration and the thorough call-by-call mapping. It was really useful when we compared approaches. We're closing this in favor of #6. We decided to store one document per session and rewrite it in full on every capture, rather than appending turn deltas, because appended resends were what caused duplicate memories in our other plugins. #6 already keys capture by session, so we're finishing V5 there on top of #8's tag fix. Your PR helped shape that work. |
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.
What
Moves the provider from the 3.x SDK to the official supermemory Python SDK 5 (
supermemory>=5.0.0,<6) and the namespace-first v5 API. Tools, config keys, environment variables, and the tool result shapes stay the same. Plugin version goes to 2.0.0 because the SDK major changes and a self-hosted server now has to serve the v5 routes.Why
SDK 5.0.0 is generated from the v5 API (Fern instead of Stainless), and the calls this provider made are gone or have changed. With SDK 5 installed, the current
mainfails on every operation, for example:'DocumentsClient' object has no attribute 'add'MemoriesClient.forget() got an unexpected keyword argument 'container_tag''function' object has no attribute 'memories'(searchis now a method)Supermemory.profile() got an unexpected keyword argument 'container_tag'Capture failures are logged at DEBUG and retried in the background, so on SDK 5 auto-capture would quietly stop working.
How each call maps
documents.add(container_tags=[tag], custom_id=…, entity_context=…)add(namespace, id=…, supporting_context=…, task_type="memory"), i.e.POST /ns/{ns}/documentsearch.memories(q=…, container_tag=…, search_mode=…)search(namespace, query=…, search_mode=…, threshold=0.6, rerank="none", rewrite_query=False)profile(container_tag=…, q=…)profile(namespace), plus a separatesearch(...)when there is a querymemories.forget(container_tag=…, id=…)memories.forget(namespace, ids=[id])with per-id confirmationWhat stays the same:
_sanitize_tagas before, including{identity}templates, theSUPERMEMORY_CONTAINER_TAGoverride, and the multi-container whitelist. Per the v5 migration guide, existing tag values are valid namespaces, so there is no data migration and no partition gets renamed.POSTwith an existingidappends or diffs into that document (PATCHwould replace it, so the provider never uses it).sm_source: hermesmetadata and thex-sm-sourceheader are unchanged.dreamingis not set, so the server default applies.rerank: "none"andrewriteQuery: false, explicitly, so recall does not silently get broader. The pre-v5search_mode: "documents"maps to v5chunks, andchunksis also accepted directly.base_urlprecedence is unchanged (supermemory.json→SUPERMEMORY_BASE_URL→ hosted). The resolved URL is always passed explicitly. An unreachable or failing self-hosted endpoint fails closed and is never retried against the hosted API.auto_capture/auto_recall, and the cron / flush / subagent write isolation, are untouched.New behavior that the migration requires:
chunkwithmemorynull. Hit text now falls backmemory→chunk→chunks[].content, so these hits no longer render as emptycontentor empty prefetch bullets.supermemory-profilewithquery), the provider fetches the profile and runs one search in parallel on a short-lived helper thread. It waits for the search at most untilapi_timeouthas passed since recall started. If one leg fails, the other is still used. Prefetch logs the failure at DEBUG, and the profile tool returns it undererrors. Only a double failure is an error.supermemory-profilewithquerynow also returns those search hits asresults(same shape assupermemory-search), since v5 has nowhere else for the query to go. Profile facts are rendered from theirmemorytext, never from the model repr.matchesis exactly[id]anderrorsis empty. Otherwise the tool returns an error rather thanforgotten: true. Forget-by-query now searches inmemoriesmode, because a hybrid top hit can be a chunk and a chunk id is not a memory id._SupermemoryClientrefuses to start. The provider stays inactive, andhermes memory statusshows e.g.supermemory 3.62.0 is installed; this provider needs supermemory>=5,<6instead of every request failing later. The check is on the major version, not an exact pin, so 5.x patch and minor releases are accepted.Delivery semantics
These are documented in the README, without promising exactly-once.
max_retries=0; the SDK 5 default is 2 and covers timeouts, connection errors, 408/409/429 and 5xx). Each provider hook sends a capture batch exactly once. A failed batch is retried by the provider on the next turn, session end, session switch, or shutdown.done, but it doesn't promise dedup for a re-sent delta, so I don't rely on it.Overlap with open PRs
memoryis null for chunk hits. The helper has the same shape as in Fix search hits dropped when the text is chunk-level #3 (_field/_memory_text), but it reads the v5 fields:memory,chunk, andchunks[].content. v5 has nocontextfield, so it isn't read. This PR doesn't claim to close Fix search hits dropped when the text is chunk-level #3; maintainers may prefer to land Fix search hits dropped when the text is chunk-level #3 first for 1.x and rebase this, or close Fix search hits dropped when the text is chunk-level #3 in favor of this.search_threshold). Not absorbed. This PR only sends the pre-v5 value (0.6) explicitly, from_SEARCH_DEFAULTS, to keep recall behavior unchanged. Expose the memory search threshold as a config key #2 could rebase to make that value configurable. Note that under v5profileno longer accepts athreshold, so Expose the memory search threshold as a config key #2's change to the profile path would move to the recall search leg.pytestand the SDK, so they could be wired into that workflow, but this PR doesn't do it.Tests
tests/(new) runs the real provider module against the real installed SDK 5: its request serializers, response models, and error mapping. Only the HTTP layer is replaced, by anhttpx.MockTransport. Sockets are blocked, and all data is synthetic. The few Hermes host modules the provider imports are stubbed, using the signatures from hermes-agent's publicagent/memory_provider.pyandtools/registry.py.tests/pytest.iniexists because the repo root is the plugin package itself.Coverage includes:
id,taskType,supportingContext,metadata.sm_source, nocontainerTags/customId/dreaming)auto_capture/auto_recalldisabled send nothing{identity}template and env override, and the custom-container whitelist (including disabled mode)chunkstext fallbackapi_timeoutwhen search is slowmemoriesbase_url/ env / hosted precedence, the auth header andx-sm-sourceon every request, and fail-closed local endpointmainwith SDK 5 gives 44 failed, 7 passed. The 7 that pass cover behavior the migration doesn't touch: the capture-disabled and cron/subagent no-write paths, the buffer cap, and the bucket id format.ruff check --select E,F,Wis clean on__init__.pyandtests/.py_compileis clean.Not covered: no maintainer CI ran, and these tests don't hit the hosted API or a self-hosted server end to end. Please treat the wire mapping as verified against the SDK's own serializers, not against a live server.
Known limitations
bucketsare not surfaced; the tool output is unchanged except forresults/errorswhen a query is given.🤖 Generated with Claude Code