Repository navigation
feat(retrieval): opt-in llm_id for GoodMem's LLM answer (0.3.0) - #3
Merged
Merged
Conversation
GoodMem can run an LLM over the retrieved chunks and stream back an abstractReply, but 0.2.1 had no way to ask for one: GoodMemToolkit(llm_id=...) raised TypeError and no request carried it, so the abstractReply the result parser could read never arrived. - GoodMemToolkit takes a developer-set llm_id, checked as a UUID at construction and again at use (GoodMemIdError, nothing sent); "" is refused with the same "pass llm_id=None" hint as reranker_id. - It is sent in the post-processor config beside reranker_id; unset, the request is unchanged. - goodmem_search returns the answer as abstractReply; the retriever puts it in every row's extra_info as goodmem_abstract_reply. Both are None when the LLM failed and absent when no LLM is configured. - goodmem_search(query, top_k) is unchanged: the model never sees it. - A failing LLM follows the status contract: hits kept, partial set, statuses [NOT_FOUND, SUMMARIZATION_FAILED] (missing LLM) or [SUMMARIZATION_FAILED] (provider 429). Scores are not relabelled; a working reranker beside a missing LLM keeps its reranker scores. Fixtures are live streams captured from GoodMem for each case. Offline 466 -> 517 (47 of the new tests fail on main), live 30 -> 35. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Summary
Adds an opt-in, developer-set
llm_idtoGoodMemToolkit, so GoodMem runs one of its LLMs over the retrieved chunks and returns a grounded answer beside the hits. It works likereranker_id: you set it at construction, and the model's toolgoodmem_search(query, top_k)does not change.GoodMemToolkit(..., llm_id="<uuid>"). It is checked with the package's single id validator (require_uuid) at construction and again at use. A non-UUID raisesGoodMemIdErrorand nothing is sent.llm_id=""is refused with a hint to passllm_id=None, the same wayreranker_idhandles it.postProcessor.config.llm_id), next toreranker_idwhen both are set. Ifllm_idis unset, the request body is byte-for-byte unchanged (the test checks there is nopostProcessor).goodmem_searchreturns the answer asabstractReply, which is also the tool result the model reads.GoodMemRetriever.query()puts it in each row'sextra_infoasgoodmem_abstract_reply. CAMEL's retriever returns a plain list of rows, so the answer is repeated on every row. Both keys are present whenever an LLM is configured, set toNoneif the LLM failed, and absent otherwise. No new public type is added:RetrievalOutcome.abstract_replyalready existed and its parser already handled the event, but nothing ever requested it.partialis set, the statuses and awarningare surfaced, and nothing is raised.FEATURE_DISABLEDandLLM_CAPABILITY_INFERREDremain informational.NOT_FOUNDnamesllm_id, not the reranker, so the reranker-fallback heuristic does not trip.What failed before, and how it behaves now
Measured against the local GoodMem server (OpenRouter
qwen/qwen3-8bLLM). The "before" rows used the publishedcamel-goodmem==0.2.1from PyPI.GoodMemToolkit(llm_id=...)TypeError: GoodMemToolkit.__init__() got an unexpected keyword argument 'llm_id'postProcessor.config.llm_idpartial, query, resultSetId, results, statuses, success, totalResults, with noabstractReplyabstractReply: "CAMEL is a framework for building communicative multi-agent systems, as indicated by the retrieved data. Its agents work together through role-playing and dialogue …". The hits are unchanged (scoreKind: vector,score == -rawScore)extra_info["goodmem_abstract_reply"]on every rowpartial: True,statuses[NOT_FOUND, SUMMARIZATION_FAILED], hits kept,abstractReply: None, no exceptionpartial: True,[SUMMARIZATION_FAILED]with the provider's429in the message, hits keptscoreKind: reranker(score == rawScore), andpartialis setllm_id(../llms/<id>,"",<uuid>\n, …)GoodMemIdErrornamingllm_id. The recording server receives nothinggoodmem_search(query, top_k){query, top_k}On main, 47 of the 51 new offline tests fail, all at
TypeError: ... unexpected keyword argument 'llm_id'. The other 4 are controls that check nothing changes whenllm_idis unset.Tests
tests/test_goodmem_toolkit.py(real SDK over a mock transport)tests/test_goodmem_ids.py(real SDK against a recording server)tests/test_goodmem_live.py(live)TestLiveLlm. They needGOODMEM_TEST_LLM_ID;GOODMEM_TEST_FAILING_LLM_IDandGOODMEM_TEST_RERANKER_IDare optional, and each test skips without its id.ruff checkandruff format --checkclean;mypy camel_goodmemclean.twine checkand an import in a clean venv pass.uv --resolution lowest-directon Python 3.10: camel-ai 0.2.79, goodmem 0.1.35, pydantic 2.11.0, mcp 1.3.0): 517 passed.Release
The version goes to 0.3.0 (a minor bump for a new opt-in feature) in
pyproject.tomland__version__. This repo does not release on merge:publish.ymlpublishes only when av*tag is pushed. Merging this PR publishes nothing; release 0.3.0 is a separate, deliberate tag.The README has a new "LLM answers" section (where the answer appears, that it is opt-in and developer-set, and what happens when the LLM fails), plus a "Changes in 0.3.0" table. The README is where this repo keeps its changelog.
🤖 Generated with Claude Code