Skip to content

fix: filter internal prompts from chat capture observations#21

Open
wjiuxing wants to merge 2 commits into
clopca:mainfrom
wjiuxing:fix/filter-internal-prompts-from-observations
Open

fix: filter internal prompts from chat capture observations#21
wjiuxing wants to merge 2 commits into
clopca:mainfrom
wjiuxing:fix/filter-internal-prompts-from-observations

Conversation

@wjiuxing
Copy link
Copy Markdown

@wjiuxing wjiuxing commented May 27, 2026

Problem

Closes #20

The chat-capture hook (chat.message) unconditionally stored all user messages as observations, including open-mem internal prompts that leak into the chat stream.

In one project database, 2330 out of 4710 observations (49%) were garbage "User request: <task>\nAnalyze the following tool output..." entries — internal extraction prompts, not user intent.

These garbage observations were injected back into context via true_memory_context, causing:

  • Token waste: ~2KB per garbage observation
  • Stale directive injection: Old [search-mode], [analyze-mode] directives re-injected into new sessions
  • Progressive degradation: Gets worse over time as more garbage accumulates

Root Cause

open-mem injects internal prompts (observation extraction, summarization, conflict evaluation, entity extraction, reranking) into the chat stream. The chat-capture hook sees these as user messages and stores them as observations with title="User request: <task>...".

Fix

Add INTERNAL_PROMPT_PATTERNS — a list of regex patterns matching all 5 internal prompt templates — to chat-capture.ts. Before creating an observation, the text is tested against these patterns and rejected if it matches.

Changes:

  • src/hooks/chat-capture.ts: +18 lines (pattern definitions + filter check)
  • tests/hooks/chat-capture.test.ts: +97 lines (4 new test cases)

Testing

✓ filters out internal observation extraction prompts
✓ filters out internal summarization prompts
✓ filters out internal conflict evaluation prompts
✓ does not filter normal user messages that happen to contain XML-like tags
✓ All 16 existing tests pass

Workaround for existing databases

For users with existing garbage observations, run:

UPDATE observations SET deleted_at = datetime('now')
WHERE title LIKE 'User request:%' AND deleted_at IS NULL;

Summary by CodeRabbit

  • Bug Fixes

    • Internal system prompts are now properly filtered and prevented from being persisted in chat history, ensuring only user-generated content is saved as observations.
  • Tests

    • Added test coverage for message filtering behavior to validate that internal prompts are correctly excluded while normal user messages are preserved.

Review Change Stack

The chat-capture hook unconditionally stored all user messages as
observations, including open-mem internal prompts (observation extraction,
summarization, conflict evaluation, etc.) that leak into the chat stream.

These prompts accumulated as garbage observations (49% of total in one
project database) and were injected back into context via
true_memory_context, wasting tokens and re-injecting stale directives.

Fix: Add INTERNAL_PROMPT_PATTERNS filter to chat-capture.ts that rejects
messages starting with known internal prompt templates before observation
creation.

Closes clopca#20
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

Warning

Review limit reached

@wjiuxing, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 55 minutes and 36 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 430134c2-0278-4076-aa9e-666261ce3a9b

📥 Commits

Reviewing files that changed from the base of the PR and between 3770626 and 3b2c790.

📒 Files selected for processing (1)
  • tests/hooks/chat-capture.test.ts
📝 Walkthrough

Walkthrough

This PR adds filtering to the chat capture hook to prevent internal system prompts from being persisted as observations. A set of regex patterns identifies internal prompts for observation extraction, session summarization, conflict evaluation, and related tasks. The persistChatMessage function now rejects messages matching these patterns. Four new tests validate that internal prompts are correctly filtered while normal user messages remain captured.

Changes

Internal Prompt Filtering for Chat Capture

Layer / File(s) Summary
Pattern definition and filtering guard
src/hooks/chat-capture.ts
INTERNAL_PROMPT_PATTERNS regex list identifies internal system prompts (observation extraction, session summarization, conflict evaluation, entity extraction, reranking). A new guard in persistChatMessage returns false when processed message text matches any pattern, preventing persistence.
Test coverage for prompt filtering
tests/hooks/chat-capture.test.ts
Four test cases validate that observation extraction, session summarization, and conflict evaluation prompts are filtered out and do not trigger observation creation, while a fourth test confirms normal user messages with XML-like tags remain unfiltered and create observations.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A rabbit hops through noisy prompts,
Filters out the system thoughts,
Keeps the real user voice so bright,
Discards the internal clutter tonight! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: filtering internal prompts from chat capture observations, which is exactly what the changeset implements.
Description check ✅ Passed The description provides a comprehensive explanation of the problem, root cause, and fix. It includes code changes, testing results, and a workaround for existing databases.
Linked Issues check ✅ Passed The code changes fully address issue #20: regex patterns filter all 5 internal prompt templates (extraction, summarization, conflict evaluation, entity extraction, reranking) before observations are created.
Out of Scope Changes check ✅ Passed All changes are directly related to the objective: the hook implementation adds internal prompt filtering, and test additions validate this filtering behavior without introducing unrelated modifications.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 27, 2026

Greptile Summary

This PR fixes a data-quality problem in the chat-capture hook where internal open-mem prompts (observation extraction, summarization, conflict evaluation, entity extraction, reranking) were being stored as user observations, accounting for ~49% garbage entries in at least one production database.

  • src/hooks/chat-capture.ts: Adds INTERNAL_PROMPT_PATTERNS (5 regexes anchored to the start of each internal prompt template) and a single filter guard in persistChatMessage that runs after privacy processing but before the observation is written.
  • tests/hooks/chat-capture.test.ts: Adds 4 new test cases covering 3 of the 5 new patterns (observation extraction, summarization, conflict evaluation) plus a negative case ensuring normal XML-containing messages still pass through. The entity_extraction and rerank_request patterns lack dedicated filter tests.

Confidence Score: 4/5

Safe to merge; the filter correctly targets all 5 internal prompt templates and cannot false-positive on normal user text due to start-anchored patterns.

The core logic in chat-capture.ts is correct and well-placed. The only gap is that two of the five new regex patterns (entity_extraction and rerank_request) have no corresponding filter tests, so a future regression there would go undetected.

tests/hooks/chat-capture.test.ts — needs filter tests for the entity_extraction and rerank_request patterns.

Important Files Changed

Filename Overview
src/hooks/chat-capture.ts Adds INTERNAL_PROMPT_PATTERNS and a pre-create filter in persistChatMessage; patterns correctly anchor to the start of each prompt template and match all 5 internal prompt types.
tests/hooks/chat-capture.test.ts Adds 4 test cases; covers 3 of 5 new patterns (observation extraction, summarization, conflict evaluation) plus a negative case — entity_extraction and rerank_request patterns are not tested.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[chat.message hook fires] --> B[extractTextFromParts]
    B --> C[stripPrivateBlocks + redactSensitive]
    C --> D{length >= MIN_MESSAGE_LENGTH?}
    D -- No --> E[return false]
    D -- Yes --> F{matches INTERNAL_PROMPT_PATTERNS?}
    F -- Yes --> G[return false filtered internal prompt]
    F -- No --> H[sessions.getOrCreate]
    H --> I[observations.create]
    I --> J[return true]
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
tests/hooks/chat-capture.test.ts:311-327
**Missing test coverage for `entity_extraction` and `rerank_request` patterns**

The PR adds 5 patterns to `INTERNAL_PROMPT_PATTERNS` but only 3 of the 5 are covered by the new "filters out…" tests. The `<entity_extraction>` and `<rerank_request>` patterns have no corresponding filter tests. If either pattern were accidentally removed or broken in a future refactor, nothing would catch the regression.

Reviews (1): Last reviewed commit: "fix: filter internal prompts from chat c..." | Re-trigger Greptile

Comment on lines +311 to +327
test("does not filter normal user messages that happen to contain XML-like tags", async () => {
const observations = makeMockObservations();
const sessions = makeMockSessions();
const hook = createChatCaptureHook(observations as never, sessions as never, "/tmp/proj");

await hook(
{ sessionID: "s1" },
{
message: {},
parts: [
"Please help me debug this HTML issue with <div> tags and also fix the layout",
],
},
);

expect(observations.calls.find((c) => c.method === "create")).toBeDefined();
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing test coverage for entity_extraction and rerank_request patterns

The PR adds 5 patterns to INTERNAL_PROMPT_PATTERNS but only 3 of the 5 are covered by the new "filters out…" tests. The <entity_extraction> and <rerank_request> patterns have no corresponding filter tests. If either pattern were accidentally removed or broken in a future refactor, nothing would catch the regression.

Prompt To Fix With AI
This is a comment left during a code review.
Path: tests/hooks/chat-capture.test.ts
Line: 311-327

Comment:
**Missing test coverage for `entity_extraction` and `rerank_request` patterns**

The PR adds 5 patterns to `INTERNAL_PROMPT_PATTERNS` but only 3 of the 5 are covered by the new "filters out…" tests. The `<entity_extraction>` and `<rerank_request>` patterns have no corresponding filter tests. If either pattern were accidentally removed or broken in a future refactor, nothing would catch the regression.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/hooks/chat-capture.test.ts (1)

235-327: ⚡ Quick win

Add coverage for the two remaining internal prompt patterns.

Current new tests cover extraction/summarization/conflict, but INTERNAL_PROMPT_PATTERNS also filters <entity_extraction> and <rerank_request>. Please add one negative test per pattern (assert observations.create is not called) to lock down all branches introduced by this fix.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/hooks/chat-capture.test.ts` around lines 235 - 327, Add two negative
tests in tests/hooks/chat-capture.test.ts mirroring the existing pattern tests:
one that passes a part containing an <entity_extraction>... payload and one that
passes a <rerank_request>... payload, both using makeMockObservations(),
makeMockSessions(), and createChatCaptureHook(...) and invoking hook({
sessionID: "s1" }, { message: {}, parts: [
"<entity_extraction>...</entity_extraction>" ] }) (and similarly for
<rerank_request>); assert that observations.calls has length 0 or that
observations.create is not called to ensure INTERNAL_PROMPT_PATTERNS filtering
covers these two cases. Ensure test names clearly state they "filter out
internal entity extraction prompts" and "filter out internal rerank request
prompts" so they follow the existing tests' style.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/hooks/chat-capture.test.ts`:
- Around line 235-327: Add two negative tests in
tests/hooks/chat-capture.test.ts mirroring the existing pattern tests: one that
passes a part containing an <entity_extraction>... payload and one that passes a
<rerank_request>... payload, both using makeMockObservations(),
makeMockSessions(), and createChatCaptureHook(...) and invoking hook({
sessionID: "s1" }, { message: {}, parts: [
"<entity_extraction>...</entity_extraction>" ] }) (and similarly for
<rerank_request>); assert that observations.calls has length 0 or that
observations.create is not called to ensure INTERNAL_PROMPT_PATTERNS filtering
covers these two cases. Ensure test names clearly state they "filter out
internal entity extraction prompts" and "filter out internal rerank request
prompts" so they follow the existing tests' style.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 598ed226-0056-4e49-b0c8-2ba1f8425e7f

📥 Commits

Reviewing files that changed from the base of the PR and between 11f9935 and 3770626.

📒 Files selected for processing (2)
  • src/hooks/chat-capture.ts
  • tests/hooks/chat-capture.test.ts

Addresses review feedback: add test cases for the two INTERNAL_PROMPT_PATTERNS
that were missing dedicated filter tests (entity_extraction and rerank_request).
@wjiuxing
Copy link
Copy Markdown
Author

Re: #21 (comment)

Good catch! Added in commit 3b2c790 — both entity_extraction and rerank_request now have dedicated filter tests. All 5 patterns are covered, 18/18 tests pass.

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.

[Bug] Internal extraction prompts captured as observations, polluting context injection

1 participant