#!/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()