Skip to content

✨ feat(user-memory): make ProfileExtractor target-aware in multi-speaker conversations#2

Closed
LoveS0ph1e wants to merge 1 commit into
EverMind-AI:mainfrom
LoveS0ph1e:feat/user-memory-target-aware-profile-extraction
Closed

✨ feat(user-memory): make ProfileExtractor target-aware in multi-speaker conversations#2
LoveS0ph1e wants to merge 1 commit into
EverMind-AI:mainfrom
LoveS0ph1e:feat/user-memory-target-aware-profile-extraction

Conversation

@LoveS0ph1e

@LoveS0ph1e LoveS0ph1e commented Jun 28, 2026

Copy link
Copy Markdown

Summary

ProfileExtractor.aextract already receives a sender_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 plain user <-> assistant exchange 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_PROMPT carries a {target_user} block and explicit speaker-attribution rules, and its module docstring notes it is "not yet consumed by ProfileExtractor - 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_extract thread target_user=sender_id into render_prompt.
  • The INIT and UPDATE prompts (en + zh) gain a **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 existing TEAM_PROFILE_UPDATE_PROMPT.
  • _render_conversation is unchanged: every line is already tagged (user_id:...), which the prompt now references to attribute by speaker - the same signal TEAM_PROFILE_UPDATE_PROMPT relies on.
  • COMPACT is left alone: it re-summarises an existing profile and never sees a conversation.

Backward compatibility

render_prompt fills placeholders by literal substitution, so the extra target_user= argument is a no-op for any template that does not reference {target_user} - including a caller-supplied prompt= override. Single-user extraction is unaffected.

Tests

  • The 17 existing ProfileExtractor tests pass unchanged.
  • 2 tests assert the target sender_id is 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 --check are clean; the profile test suite is 19 passed against a clean everalgo-user-memory==0.3.1. mypy / pyright were 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.

@LoveS0ph1e
LoveS0ph1e force-pushed the feat/user-memory-target-aware-profile-extraction branch from 4fea8d5 to 35b202f Compare June 28, 2026 11:23
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
LoveS0ph1e force-pushed the feat/user-memory-target-aware-profile-extraction branch from 35b202f to 79af698 Compare July 2, 2026 04:02
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.
@LoveS0ph1e

Copy link
Copy Markdown
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.

@LoveS0ph1e LoveS0ph1e closed this Jul 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant