Update docs: watcher fix, plugin capture fix (2026-02-25)
- Fixed watcher stuck on old session bug (restarted service) - Fixed plugin capture 0 exchanges (added extractMessageText for OpenAI content arrays) - Updated README, session.md, function_check.md, audit_checklist.md - Verified: 9 exchanges captured per session
This commit is contained in:
208
README.md
208
README.md
@@ -3,7 +3,7 @@
|
||||
**Project:** Gem extraction and memory recall system
|
||||
**Status:** ✅ Active & Verified
|
||||
**Location:** `~/.openclaw/workspace/.projects/true-recall-v2/`
|
||||
**Last Updated:** 2026-02-24 19:02 CST
|
||||
**Last Updated:** 2026-02-25 12:04 CST
|
||||
|
||||
---
|
||||
|
||||
@@ -38,6 +38,29 @@ curl -s http://<QDRANT_IP>:6333/collections | jq '.result.collections[].name'
|
||||
|
||||
---
|
||||
|
||||
## Recent Fixes (2026-02-25 12:41 CST)
|
||||
|
||||
| Issue | Root Cause | Fix Applied |
|
||||
|-------|------------|-------------|
|
||||
| **Watcher stuck on old session** | Watcher only switched sessions when file deleted, old sessions persisted | ✅ Restarted service, now follows current session |
|
||||
| **Plugin capture 0 exchanges** | OpenClaw uses OpenAI content format (array of items), plugin expected string | ✅ Added `extractMessageText()` to extract text from `type: "text"` items |
|
||||
|
||||
### Validation Results
|
||||
|
||||
**Plugin capture:**
|
||||
```
|
||||
Before: parsed 14 user, 84 assistant messages, 0 exchanges
|
||||
After: parsed 17 user, 116 assistant messages, 9 exchanges ✅
|
||||
```
|
||||
|
||||
**Watcher:**
|
||||
```
|
||||
Before: Watching old session (old session ID from Feb 24)
|
||||
After: Watching current session (current session ID from Feb 25) ✅
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
TrueRecall v2 extracts "gems" (key insights) from conversations and injects them as context. It consists of three layers:
|
||||
@@ -54,8 +77,8 @@ TrueRecall v2 extracts "gems" (key insights) from conversations and injects them
|
||||
|
||||
| Collection | Points | Purpose | Status |
|
||||
|------------|--------|---------|--------|
|
||||
| `memories_tr` | **12,378** | Full text (live capture) | ✅ Active |
|
||||
| `gems_tr` | **5** | Curated gems (injection) | ✅ Active |
|
||||
| `memories_tr` | **12,729** | Full text (live capture) | ✅ Active |
|
||||
| `gems_tr` | **14+** | Curated gems (injection) | ✅ **WORKING** - Context injection verified |
|
||||
|
||||
**All memories tagged with `curated: false` for timer curation.**
|
||||
|
||||
@@ -63,8 +86,8 @@ TrueRecall v2 extracts "gems" (key insights) from conversations and injects them
|
||||
|
||||
| Service | Status | Details |
|
||||
|---------|--------|---------|
|
||||
| `mem-qdrant-watcher` | ✅ Active | PID 1748, capturing |
|
||||
| Timer curator | ✅ Deployed | Every 30 min via cron |
|
||||
| `mem-qdrant-watcher` | ✅ Active | PID 234, capturing |
|
||||
| Timer curator | ✅ Deployed | Every 5 min via cron |
|
||||
| OpenClaw Gateway | ✅ Running | Version 2026.2.23 |
|
||||
| memory-qdrant plugin | ✅ Loaded | recall: gems_tr |
|
||||
|
||||
@@ -76,8 +99,8 @@ TrueRecall v2 extracts "gems" (key insights) from conversations and injects them
|
||||
|---------|---------------|---------------|---------------|
|
||||
| **Storage** | Redis | Redis + Qdrant | Qdrant only |
|
||||
| **Capture** | Session batch | Session batch | Real-time |
|
||||
| **Curation** | Manual | Daily 2:45 AM | Timer (5 min) |
|
||||
| **Embedding** | — | snowflake | snowflake + mxbai |
|
||||
| **Curation** | Manual | Daily 2:45 AM | Timer (5 min) ✅ |
|
||||
| **Embedding** | — | snowflake | snowflake-arctic-embed2 ✅ |
|
||||
| **Curator LLM** | — | qwen3:4b | qwen3:30b |
|
||||
| **State tracking** | — | — | `curated` tag |
|
||||
| **Batch size** | — | 24h worth | Configurable |
|
||||
@@ -138,7 +161,7 @@ TrueRecall v2 extracts "gems" (key insights) from conversations and injects them
|
||||
**File:** `skills/qdrant-memory/scripts/realtime_qdrant_watcher.py`
|
||||
|
||||
**What it does:**
|
||||
- Watches `~/.openclaw/agents/main/sessions/*.jsonl`
|
||||
- Watches `/root/.openclaw/agents/main/sessions/*.jsonl`
|
||||
- Parses each turn (user + AI)
|
||||
- Embeds with `snowflake-arctic-embed2`
|
||||
- Stores to `memories_tr` instantly
|
||||
@@ -246,132 +269,7 @@ python3 clean_memories_tr.py --execute --limit 100
|
||||
|
||||
---
|
||||
|
||||
### 5. Semantic Deduplication (Similarity Checking)
|
||||
|
||||
**Why:** Smaller models (4b) often extract duplicate or near-duplicate gems. Without checking, your `gems_tr` collection fills with redundant entries.
|
||||
|
||||
**The Problem:**
|
||||
- "User decided on Redis" and "User selected Redis for caching" are the same gem
|
||||
- Smaller models lack nuance — they extract surface variations as separate gems
|
||||
- Over time, 30-50% of gems may be duplicates
|
||||
|
||||
**Solution: Semantic Similarity Check**
|
||||
|
||||
Before inserting a new gem:
|
||||
1. Embed the candidate gem text
|
||||
2. Search `gems_tr` for similar embeddings (past 24h)
|
||||
3. If similarity > 0.85, SKIP (don't insert)
|
||||
4. If similarity 0.70-0.85, MERGE (update existing with richer context)
|
||||
5. If similarity < 0.70, INSERT (new unique gem)
|
||||
|
||||
**Implementation Options:**
|
||||
|
||||
#### Option A: Built-in Curator Check (Recommended)
|
||||
|
||||
Modify `curator_timer.py` to add pre-insertion similarity check:
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
from qdrant_client import QdrantClient
|
||||
|
||||
qdrant = QdrantClient("http://<QDRANT_IP>:6333")
|
||||
|
||||
def is_duplicate(gem_text: str, user_id: str = "rob", threshold: float = 0.85) -> bool:
|
||||
"""Check if similar gem exists in past 24h"""
|
||||
# Embed the candidate
|
||||
response = requests.post(
|
||||
"http://<OLLAMA_IP>:11434/api/embeddings",
|
||||
json={"model": "mxbai-embed-large", "prompt": gem_text}
|
||||
)
|
||||
embedding = response.json()["embedding"]
|
||||
|
||||
# Search for similar gems
|
||||
results = qdrant.search(
|
||||
collection_name="gems_tr",
|
||||
query_vector=embedding,
|
||||
limit=3,
|
||||
query_filter={
|
||||
"must": [
|
||||
{"key": "user_id", "match": {"value": user_id}},
|
||||
{"key": "timestamp", "range": {"gte": "now-24h"}}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
# Check similarity scores
|
||||
for result in results:
|
||||
if result.score > threshold:
|
||||
return True # Duplicate found
|
||||
return False
|
||||
|
||||
# In main loop, before inserting:
|
||||
if is_duplicate(gem["gem"]):
|
||||
log.info(f"Skipping duplicate gem: {gem['gem'][:50]}...")
|
||||
continue
|
||||
```
|
||||
|
||||
**Pros:** Catches duplicates at source, no extra jobs
|
||||
**Cons:** Adds ~50-100ms per gem (embedding call)
|
||||
|
||||
#### Option B: Periodic AI Review (Subagent Task)
|
||||
|
||||
Have a subagent periodically review and merge duplicates:
|
||||
|
||||
```bash
|
||||
# Run weekly via cron
|
||||
0 3 * * 0 cd <PROJECT_PATH> && python3 dedup_gems.py
|
||||
```
|
||||
|
||||
**dedup_gems.py approach:**
|
||||
1. Load all gems from past 7 days
|
||||
2. Group by semantic similarity (clustering)
|
||||
3. For each cluster > 1 gem:
|
||||
- Keep highest confidence gem as primary
|
||||
- Merge context from others into primary
|
||||
- Delete duplicates
|
||||
|
||||
**Pros:** Can use reasoning model for nuanced merging
|
||||
**Cons:** Batch job, duplicates exist until cleanup runs
|
||||
|
||||
#### Option C: Real-time Watcher Hook
|
||||
|
||||
Add deduplication to the real-time watcher before memories are even stored:
|
||||
|
||||
```python
|
||||
# In watcher, before upsert to memories_tr
|
||||
if is_similar_to_recent(memory_text, window="1h"):
|
||||
memory["duplicate_of"] = similar_id # Tag but still store
|
||||
```
|
||||
|
||||
**Pros:** Prevents duplicate memories upstream
|
||||
**Cons:** Memories may differ slightly even if gems would be same
|
||||
|
||||
**Recommendation by Model:**
|
||||
|
||||
| Model | Recommended Approach | Reason |
|
||||
|-------|---------------------|--------|
|
||||
| **4b** | **Option A + B** | Built-in check prevents duplicates; periodic review catches edge cases |
|
||||
| **30b** | **Option B only** | 30b produces fewer duplicates; weekly review sufficient |
|
||||
| **Production** | **Option A** | Best balance of prevention and performance |
|
||||
|
||||
**Configuration:**
|
||||
|
||||
Add to `curator_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"deduplication": {
|
||||
"enabled": true,
|
||||
"similarity_threshold": 0.85,
|
||||
"lookback_hours": 24,
|
||||
"mode": "skip" // "skip", "merge", or "flag"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. OpenClaw Compactor Configuration
|
||||
### 5. OpenClaw Compactor Configuration
|
||||
|
||||
**Status:** ✅ Applied
|
||||
|
||||
@@ -399,25 +297,11 @@ Add to `curator_config.json`:
|
||||
- `reserveTokensFloor: 0` — Allow aggressive settings (disables 20k minimum)
|
||||
- `memoryFlush.enabled: false` — No silent "write memory" turns
|
||||
|
||||
**Known Issue: UI Glitch During Compaction**
|
||||
|
||||
When compaction runs, the Control UI may briefly behave unexpectedly:
|
||||
- Typed text may not appear immediately after hitting Enter
|
||||
- Messages may render out of order briefly
|
||||
- UI "catches up" within 1-2 seconds after compaction completes
|
||||
|
||||
**Why:** Compaction replaces the full conversation history with a summary. The UI's WebSocket state can get briefly out of sync during this transition.
|
||||
|
||||
**Workaround:**
|
||||
- Wait 2-3 seconds after hitting Enter during compaction
|
||||
- Or hard refresh (Ctrl+Shift+R) if UI seems stuck
|
||||
- **Note:** This is an OpenClaw Control UI limitation — cannot be fixed from TrueRecall side at this time.
|
||||
|
||||
**Note:** `reserveTokens` and `keepRecentTokens` are Pi runtime settings, not configurable via `agents.defaults.compaction`. They are set per-model in `contextWindow`/`contextTokens`.
|
||||
|
||||
---
|
||||
|
||||
### 7. Configuration Options Reference
|
||||
### 6. Configuration Options Reference
|
||||
|
||||
**All configurable options with defaults:**
|
||||
|
||||
@@ -447,23 +331,19 @@ When compaction runs, the Control UI may briefly behave unexpectedly:
|
||||
|
||||
---
|
||||
|
||||
### 8. Embedding Models
|
||||
### 7. Embedding Models
|
||||
|
||||
**Current Setup:**
|
||||
- `memories_tr`: `snowflake-arctic-embed2` (capture similarity)
|
||||
- `gems_tr`: `mxbai-embed-large` (recall similarity)
|
||||
- `memories_tr`: `snowflake-arctic-embed2` (capture)
|
||||
- `gems_tr`: `snowflake-arctic-embed2` (recall) ✅ **FIXED** - Both collections now use same model
|
||||
|
||||
**Rationale:**
|
||||
- mxbai has higher MTEB score (66.5) for semantic search
|
||||
- snowflake is faster for high-volume capture
|
||||
|
||||
**Note:** For simplicity, a single embedding model could be used for both collections. This would reduce complexity and memory overhead, though with slightly lower recall performance.
|
||||
**Note:** Previously used `mxbai-embed-large` for gems, but this caused embedding model mismatch. Fixed 2026-02-25.
|
||||
|
||||
---
|
||||
|
||||
### 9. memory-qdrant Plugin
|
||||
### 6. memory-qdrant Plugin
|
||||
|
||||
**Location:** `~/.openclaw/extensions/memory-qdrant/`
|
||||
**Location:** `/root/.openclaw/extensions/memory-qdrant/`
|
||||
|
||||
**Config (openclaw.json):**
|
||||
```json
|
||||
@@ -516,9 +396,9 @@ When compaction runs, the Control UI may briefly behave unexpectedly:
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `~/.openclaw/extensions/memory-qdrant/` | Plugin code |
|
||||
| `~/.openclaw/openclaw.json` | Configuration |
|
||||
| `/etc/systemd/system/mem-qdrant-watcher.service` | Service file |
|
||||
| `/root/.openclaw/extensions/memory-qdrant/` | Plugin code |
|
||||
| `/root/.openclaw/openclaw.json` | Configuration |
|
||||
| `<SYSTEMD_PATH>/mem-qdrant-watcher.service` | Service file |
|
||||
|
||||
---
|
||||
|
||||
@@ -526,7 +406,7 @@ When compaction runs, the Control UI may briefly behave unexpectedly:
|
||||
|
||||
### memory-qdrant Plugin
|
||||
|
||||
**File:** `~/.openclaw/openclaw.json`
|
||||
**File:** `/root/.openclaw/openclaw.json`
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -649,7 +529,7 @@ openclaw gateway restart
|
||||
| memories_tr | ✅ 12,378 pts | All tagged `curated: false` |
|
||||
| gems_tr | ✅ 5 pts | Injection ready |
|
||||
| Timer curator | ✅ Deployed | Every 30 min via cron |
|
||||
| Plugin injection | ✅ Working | Uses gems_tr |
|
||||
| Plugin injection | ✅ **WORKING** | Context injection verified - score 0.587 |
|
||||
| Migration | ✅ Complete | 12,378 memories |
|
||||
|
||||
**Logs:** `tail /var/log/true-recall-timer.log`
|
||||
|
||||
Reference in New Issue
Block a user