Initial commit: TrueRecall v2.2 with 30b curator and timer-based curation
This commit is contained in:
105
tr-compact/hook.py
Normal file
105
tr-compact/hook.py
Normal file
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
TrueRecall v2 - Compaction Hook
|
||||
Fast Redis queue push for compaction events
|
||||
|
||||
Called by OpenClaw session_before_compact hook
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import redis
|
||||
from datetime import datetime
|
||||
from typing import List, Dict, Any
|
||||
|
||||
# Redis config
|
||||
REDIS_HOST = "10.0.0.36"
|
||||
REDIS_PORT = 6379
|
||||
REDIS_DB = 0
|
||||
QUEUE_KEY = "tr:compact_queue"
|
||||
TAG_PREFIX = "tr:processed"
|
||||
|
||||
def get_redis_client():
|
||||
return redis.Redis(
|
||||
host=REDIS_HOST,
|
||||
port=REDIS_PORT,
|
||||
db=REDIS_DB,
|
||||
decode_responses=True
|
||||
)
|
||||
|
||||
def tag_turns(messages: List[Dict], user_id: str = "rob"):
|
||||
"""Tag turns so v1 daily curator skips them"""
|
||||
r = get_redis_client()
|
||||
pipe = r.pipeline()
|
||||
|
||||
for msg in messages:
|
||||
conv_id = msg.get("conversation_id", "unknown")
|
||||
turn = msg.get("turn", 0)
|
||||
tag_key = f"{TAG_PREFIX}:{conv_id}:{turn}"
|
||||
pipe.setex(tag_key, 86400, "1") # 24h TTL
|
||||
|
||||
pipe.execute()
|
||||
|
||||
def queue_messages(messages: List[Dict], user_id: str = "rob"):
|
||||
"""Push messages to Redis queue for background processing"""
|
||||
r = get_redis_client()
|
||||
|
||||
queue_item = {
|
||||
"user_id": user_id,
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"message_count": len(messages),
|
||||
"messages": messages
|
||||
}
|
||||
|
||||
# LPUSH to queue (newest first)
|
||||
r.lpush(QUEUE_KEY, json.dumps(queue_item))
|
||||
|
||||
return len(messages)
|
||||
|
||||
def process_compaction_event(event_data: Dict):
|
||||
"""
|
||||
Process session_before_compact event from OpenClaw
|
||||
|
||||
Expected event_data:
|
||||
{
|
||||
"session_id": "uuid",
|
||||
"user_id": "rob",
|
||||
"messages_being_compacted": [
|
||||
{"role": "user", "content": "...", "turn": 1, "conversation_id": "..."},
|
||||
...
|
||||
],
|
||||
"compaction_reason": "context_limit"
|
||||
}
|
||||
"""
|
||||
user_id = event_data.get("user_id", "rob")
|
||||
messages = event_data.get("messages_being_compacted", [])
|
||||
|
||||
if not messages:
|
||||
return {"status": "ok", "queued": 0, "reason": "no_messages"}
|
||||
|
||||
# Tag turns for v1 coordination
|
||||
tag_turns(messages, user_id)
|
||||
|
||||
# Queue for background processing
|
||||
count = queue_messages(messages, user_id)
|
||||
|
||||
return {
|
||||
"status": "ok",
|
||||
"queued": count,
|
||||
"user_id": user_id,
|
||||
"queue_key": QUEUE_KEY
|
||||
}
|
||||
|
||||
def main():
|
||||
"""CLI entry point - reads JSON from stdin"""
|
||||
try:
|
||||
event_data = json.load(sys.stdin)
|
||||
result = process_compaction_event(event_data)
|
||||
print(json.dumps(result))
|
||||
sys.exit(0)
|
||||
except Exception as e:
|
||||
print(json.dumps({"status": "error", "error": str(e)}))
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user