✨ feat(user-memory): make ProfileExtractor target-aware in multi-speaker conversations#2
Closed
LoveS0ph1e wants to merge 1 commit into
Conversation
LoveS0ph1e
force-pushed
the
feat/user-memory-target-aware-profile-extraction
branch
from
June 28, 2026 11:23
4fea8d5 to
35b202f
Compare
Replace the earlier prose anti-bloat rule with the HARD RULE version from PR EverMind-AI#3, so the two changes compose cleanly without merge conflicts on rule 6. No other changes — targeting code and prompts are unchanged.
LoveS0ph1e
force-pushed
the
feat/user-memory-target-aware-profile-extraction
branch
from
July 2, 2026 04:02
35b202f to
79af698
Compare
LoveS0ph1e
added a commit
to LoveS0ph1e/EverAlgo
that referenced
this pull request
Jul 2, 2026
… copying the first fact Rebased onto targeting + HARD RULE anti-bloat (PRs EverMind-AI#2 + EverMind-AI#3). Profile.summary was a verbatim copy of the first explicit_info description: the extraction prompts never requested a summary, and _build_summary just returned explicit_info[0]. With this change the prompts request a short paragraph summary, _resolve_summary prefers it, and _build_summary returns "" as the intentional empty fallback — downstream synthesis handles the true holistic portrait. Additive and backward-compatible: callers and prompt overrides that omit summary keep the previous behaviour, and all existing tests pass with updated assertions.
LoveS0ph1e
added a commit
to LoveS0ph1e/EverAlgo
that referenced
this pull request
Jul 2, 2026
… copying the first fact Rebased onto targeting + HARD RULE anti-bloat (PRs EverMind-AI#2 + EverMind-AI#3). Profile.summary was a verbatim copy of the first explicit_info description: the extraction prompts never requested a summary, and _build_summary just returned explicit_info[0]. With this change the prompts request a short paragraph summary, _resolve_summary prefers it, and _build_summary returns "" as the intentional empty fallback — downstream synthesis handles the true holistic portrait. Additive and backward-compatible: callers and prompt overrides that omit summary keep the previous behaviour, and all existing tests pass with updated assertions.
Author
|
Superseded by #4. The target-aware extraction core is preserved there, re-cut as a minimal diff (no whole-file rewrite), extended to zh parity, with a genuine multi-speaker test (asserting attribution keys on user_id, not display name) and an English code comment on the timestamp coarsening. Closing in favor of #4. |
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
ProfileExtractor.aextractalready receives asender_id- the user the profile is for - but that id never reaches the extraction prompt. INIT and UPDATE are rendered with{conversation_text}alone, so the model is asked to "build the user's profile" from a transcript without being told which speaker is the subject. In any slice with more than one speaker - and a plainuser <-> assistantexchange already qualifies - facts from another participant, or the assistant's own persona, can be attached to the profile owner.The repository already anticipates this.
TEAM_PROFILE_UPDATE_PROMPTcarries a{target_user}block and explicit speaker-attribution rules, and its module docstring notes it is "not yet consumed byProfileExtractor- kept for future minor extractor releases." This PR realises that intent on the active INIT and UPDATE paths, and generalises it: the problem is not specific to group chats - every conversation has at least a user and an assistant.Changes
_init_extract/_update_extractthreadtarget_user=sender_idintorender_prompt.**TARGET USER: user_id={target_user}**block and a sharper attribution rule - extract the target's facts only; every other participant, the assistant included, is context, never the subject. The wording mirrors the existingTEAM_PROFILE_UPDATE_PROMPT._render_conversationis unchanged: every line is already tagged(user_id:...), which the prompt now references to attribute by speaker - the same signalTEAM_PROFILE_UPDATE_PROMPTrelies on.COMPACTis left alone: it re-summarises an existing profile and never sees a conversation.Backward compatibility
render_promptfills placeholders by literal substitution, so the extratarget_user=argument is a no-op for any template that does not reference{target_user}- including a caller-suppliedprompt=override. Single-user extraction is unaffected.Tests
ProfileExtractortests pass unchanged.sender_idis rendered into the INIT and UPDATE prompts. As a discrimination check they fail against the unmodified extractor and pass with this change.ruff check/ruff format --checkare clean; the profile test suite is 19 passed against a cleaneveralgo-user-memory==0.3.1.mypy/pyrightwere not run locally (no workspace tooling) - please let CI confirm.Rebase note (2026-07-02): This branch was rebased onto the anti-bloat HARD RULE PR (#3).
Rule 6 now carries the HARD RULE version with IF/THEN logic and WRONG/RIGHT examples, verified
in production (deepseek-v4-flash: 3/3 clean vs baseline 0/3). No other content changed.