feat(user-memory): target-aware profile extraction + anti-bloat durable-abstraction rule (en+zh)#4
Open
LoveS0ph1e wants to merge 1 commit into
Conversation
…le-abstraction rule (en+zh)
Thread the existing sender_id into the INIT and UPDATE profile prompts as
target_user so extraction attributes each fact to the speaker who stated it
(lines are tagged (user_id:...)), keeping other participants and the AI
assistant as context only. Prevents cross-speaker contamination in group
conversations. render_prompt tolerates the extra field, so caller prompt=
overrides that omit {target_user} remain no-op-safe.
Add a durable-abstraction HARD RULE to both INIT and UPDATE prompts: each
description must be a timeless generalization (no date/weekday/clock time;
coarse time only in evidence), and repeated instances of a pattern must be
folded into one item via update rather than appended as dated clauses.
Coarsen _render_conversation per-message timestamps to date granularity.
Applied symmetrically to en and zh prompts. Adds a multi-speaker test
asserting attribution keys on user_id (not display name). CHANGELOG updated.
This was referenced Jul 5, 2026
Closed
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
This PR makes
ProfileExtractortarget-aware in multi-speaker conversations and adds a durable-abstraction (anti-bloat) rule to the profile prompts, applied symmetrically to both English and Chinese. It consolidates and supersedes three earlier, overlapping PRs (#1, #2, #3) into one clean, minimal, reviewable change.Motivation
Two independent quality problems surfaced when running
ProfileExtractoron real group chats:descriptionfields accumulated dated, event-log-style entries ("On 2026-06-29 …; on 2026-07-01 …") instead of stable generalizations, diluting the profile and hurting readability/retrieval.What changed
profile.py,prompts/{en,zh}/profile.py): thesender_idalready passed toaextractis now threaded into the INIT and UPDATE prompts astarget_user. Each conversation line is tagged(user_id:...); the prompts instruct the model to attribute every fact to its stated speaker and to treat all other participants — and the assistant — as context, never the profile's subject. Attribution keys onuser_id, not the display name.descriptionmust be a timeless generalization — no date/weekday/clock time (coarse time belongs inevidence); repeated instances of a pattern must be folded into one existing item viaupdaterather than appended as new dated clauses. Includes WRONG/RIGHT examples and a pre-output self-check._render_conversation): per-message timestamps are rendered at date granularity (YYYY-MM-DD). Profile extraction needs no intraday precision; this removes second-level noise, avoids UTC/local intraday misreads, and reinforces the no-clock-time rule.user_idis threaded into the prompt and that_render_conversationtags each speaker with their ownuser_id(so attribution keys on id, not name).[Unreleased].Backward-compatible:
render_promptperforms key-wise substitution and tolerates extra fields, so a caller-suppliedprompt=override that omits{target_user}remains a no-op. No public signatures change.Relationship to prior PRs (this supersedes #1, #2, #3)
These changes previously existed as three entangled PRs against the same two files; consolidating them removes mutual conflicts and cleans up the issues found in an audit:
Profile.summary) — intentionally not carried forward. Its summary implementation had a blocking defect (an undefinedllm_summaryreference on the UPDATE path) and bundled the other two PRs' changes. The valid insight — that copyingexplicit_info[0]as the summary produces a misleading pseudo-summary — remains open; a clean upstream fix would add asummaryfield to the prompt output schema (so_build_summary's fallback is no longer the only source). Left as follow-up rather than shipped unproven. Superseded (closed in favor of this PR).Validation
{target_user}and the anti-bloat rule are present in INIT and UPDATE for both en and zh.render_promptsubstitutestarget_user, unescapes the literal JSON braces in the examples, and leaves no stray placeholders.user_id.uvworkspace test harness was not run in the authoring environment; CI should exercise the full suite.