You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The assistant has amnesia. It has no concept of a user — only anonymous chat_id sessions — so a student who has spent weeks asking about tajweed at a beginner level starts from zero in every new conversation, and a long conversation loses its earliest (often most important) context the moment any history cap lands. This issue adds a personalization memory layer: an optional user_id on chat requests, a per-user long-term memory (knowledge level, madhhab preference, preferred language, topics studied, standing facts the user shared) that is extracted from conversations and injected into future sessions, and summarization-based compaction that folds old turns into a running summary instead of discarding them. This is what turns a stateless Q&A endpoint into a tutor that knows its student.
Current state
There is no user identity anywhere in the service: ChatRequest (main.py, lines 79–82) carries prompt, chat_id, and context only. Two conversations by the same person are unrelatable.
The DeenBridge backend (dnb-backend) has authenticated users, so the frontend can supply a stable user identifier — the AI service just never asks for one.
Memory store — a memory.py module behind a small interface with two backends: the same Redis the session-persistence issue ([Enhancement] Persist chat sessions instead of holding them in process memory #3) targets (REDIS_URL), and an in-memory/dict fallback for local dev and tests. Schema: a structured profile (knowledge_level, madhhab, language, topics_studied with recency, plus a bounded list of free-form remembered facts like "is a new convert", "studying for an exam"), each entry carrying a timestamp. Cap the profile size (e.g. max N facts, LRU/oldest-out) so it cannot grow unboundedly.
Memory extraction — after a conversation turn completes (or every K turns — justify the trigger), run a cheap structured-output Gemini call over the recent exchange that proposes profile updates ("user said they follow the Maliki school", "asked third question about inheritance — add topic"). Apply updates through validation (e.g. madhhab must be a known value — reuse normalization from the madhhab-awareness issue if both land). Run extraction outside the request's critical path (background task via FastAPI's BackgroundTasks or equivalent) so chat latency is unaffected.
Memory injection — when a session starts (or on each request for stateless-per-request designs), render the profile into a compact, clearly delimited context block ("Known about this student: …") appended to the system context — never into the user turn, and written so it composes with the injection-hardening work in [Bug] Islamic system prompt is skipped for plain requests and easily overridden by prompt injection #5 (data, not instructions).
Privacy controls — memory is personal data about a person's religious life; treat it accordingly: GET /memory/{user_id} returns the stored profile (transparency), DELETE /memory/{user_id} erases it completely, a remember: bool = True request flag lets a caller mark a conversation as do-not-learn, and profile entries carry TTL (env-configurable, e.g. MEMORY_TTL_DAYS). Never log profile contents at INFO level.
Tests — extraction-application logic against a fake store and mocked model (proposed updates validated, capped, timestamped); injection rendering; compaction seam (summary replaces evicted turns and is preserved thereafter); privacy endpoints (get/delete/opt-out). All offline; CI stays green.
Acceptance criteria
Requests without user_id behave byte-for-byte like today; with user_id, a fact established in one conversation (e.g. "I'm a beginner") measurably shapes a new conversation's answer (manually demonstrated in the PR, plus injected-context unit assertions).
Memory extraction runs off the critical path — /chat latency shows no added model call in the request/response timeline.
The profile is bounded (size cap + TTL) and every entry is timestamped; validation rejects malformed extraction proposals.
A conversation driven past the history budget retains earlier established facts via the pinned summary — the model correctly answers a question about something said before the eviction point.
GET/DELETE memory endpoints work; remember: false conversations leave no trace; profile contents never appear in INFO logs.
Redis and in-memory backends pass the same test suite; store selection via REDIS_URL presence is documented in the README env-var table.
CI stays green with new modules linted and tested.
CI (.github/workflows/ci.yml) lints only main.py and has no pytest step — extend both. PRs target the dev branch (see CONTRIBUTING.md).
Difficulty
High — background extraction with validation, a two-backend store, compaction that must interlock cleanly with a separately-assigned truncation issue, personalization that respects prompt-injection boundaries, and privacy endpoints — all with a hard requirement that anonymous traffic is completely unaffected.
🏆 GrantFox OSS — Official Campaign | FWC26. Apply for this issue through the GrantFox campaign page. The maintainer assigns one contributor before work starts; unassigned PRs may not be reviewed. PRs target the dev branch. Quality bar: CI must stay green.
💬 Questions or need help? Reach the maintainers and other contributors on the DeenBridge Telegram: https://t.me/+nst9lXNj1wc4ZDE0
Summary
The assistant has amnesia. It has no concept of a user — only anonymous
chat_idsessions — so a student who has spent weeks asking about tajweed at a beginner level starts from zero in every new conversation, and a long conversation loses its earliest (often most important) context the moment any history cap lands. This issue adds a personalization memory layer: an optionaluser_idon chat requests, a per-user long-term memory (knowledge level, madhhab preference, preferred language, topics studied, standing facts the user shared) that is extracted from conversations and injected into future sessions, and summarization-based compaction that folds old turns into a running summary instead of discarding them. This is what turns a stateless Q&A endpoint into a tutor that knows its student.Current state
ChatRequest(main.py, lines 79–82) carriesprompt,chat_id, andcontextonly. Two conversations by the same person are unrelatable.active_chatsdict (line 54), keyed bychat_id, and are wiped on every restart. Issue [Enhancement] Persist chat sessions instead of holding them in process memory #3 covers moving session history to an external store (Redis); it does not add user identity or any cross-session memory.dnb-backend) has authenticated users, so the frontend can supply a stable user identifier — the AI service just never asks for one.What to build
user_idon requests — adduser_id: Optional[str]toChatRequest. Nouser_id→ exactly today's stateless behavior; memory features activate only when it is present. Treat it as an opaque string (auth/API-key work is issue [Enhancement] Add service API-key auth and rate limiting to protect the Gemini quota #9's scope, not this one).memory.pymodule behind a small interface with two backends: the same Redis the session-persistence issue ([Enhancement] Persist chat sessions instead of holding them in process memory #3) targets (REDIS_URL), and an in-memory/dict fallback for local dev and tests. Schema: a structured profile (knowledge_level,madhhab,language,topics_studiedwith recency, plus a bounded list of free-form remembered facts like "is a new convert", "studying for an exam"), each entry carrying a timestamp. Cap the profile size (e.g. max N facts, LRU/oldest-out) so it cannot grow unboundedly.BackgroundTasksor equivalent) so chat latency is unaffected.GET /memory/{user_id}returns the stored profile (transparency),DELETE /memory/{user_id}erases it completely, aremember: bool = Truerequest flag lets a caller mark a conversation as do-not-learn, and profile entries carry TTL (env-configurable, e.g.MEMORY_TTL_DAYS). Never log profile contents at INFO level.Acceptance criteria
user_idbehave byte-for-byte like today; withuser_id, a fact established in one conversation (e.g. "I'm a beginner") measurably shapes a new conversation's answer (manually demonstrated in the PR, plus injected-context unit assertions)./chatlatency shows no added model call in the request/response timeline.GET/DELETEmemory endpoints work;remember: falseconversations leave no trace; profile contents never appear in INFO logs.REDIS_URLpresence is documented in the README env-var table.Pointers
main.py—ChatRequest(lines 79–82),active_chats(line 54), the/chathandler (lines 118–184),DELETE /chat/{chat_id}(lines 187–198)..github/workflows/ci.yml) lints onlymain.pyand has no pytest step — extend both. PRs target thedevbranch (seeCONTRIBUTING.md).Difficulty
High — background extraction with validation, a two-backend store, compaction that must interlock cleanly with a separately-assigned truncation issue, personalization that respects prompt-injection boundaries, and privacy endpoints — all with a hard requirement that anonymous traffic is completely unaffected.
🏆 GrantFox OSS — Official Campaign | FWC26. Apply for this issue through the GrantFox campaign page. The maintainer assigns one contributor before work starts; unassigned PRs may not be reviewed. PRs target the
devbranch. Quality bar: CI must stay green.💬 Questions or need help? Reach the maintainers and other contributors on the DeenBridge Telegram: https://t.me/+nst9lXNj1wc4ZDE0