mirror of
https://github.com/blackboxprogramming/remember.git
synced 2026-03-17 03:57:10 -05:00
Merge pull request #7 from blackboxprogramming/codex/proceed-to-next-step
Add utilities and tests for contradiction log
This commit is contained in:
@@ -7,10 +7,12 @@ The intent is to build a transparent record for later analysis.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import time
|
||||
from dataclasses import dataclass, asdict
|
||||
from typing import List
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -22,17 +24,19 @@ class ContradictionEntry:
|
||||
|
||||
class ContradictionLog:
|
||||
def __init__(self, path: str = "contradiction_log.jsonl") -> None:
|
||||
self.path = path
|
||||
self.path = Path(path)
|
||||
self.path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def append(self, prompt: str, reply: str) -> None:
|
||||
entry = ContradictionEntry(time.time(), prompt, reply)
|
||||
with open(self.path, "a", encoding="utf-8") as f:
|
||||
self.path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with self.path.open("a", encoding="utf-8") as f:
|
||||
f.write(json.dumps(asdict(entry)) + "\n")
|
||||
|
||||
def read_all(self) -> List[ContradictionEntry]:
|
||||
entries: List[ContradictionEntry] = []
|
||||
try:
|
||||
with open(self.path, "r", encoding="utf-8") as f:
|
||||
with self.path.open("r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = json.loads(line.strip())
|
||||
entries.append(ContradictionEntry(**data))
|
||||
@@ -40,6 +44,27 @@ class ContradictionLog:
|
||||
pass
|
||||
return entries
|
||||
|
||||
def to_dicts(self) -> List[dict]:
|
||||
"""Return log entries as dictionaries for serialization or inspection."""
|
||||
return [asdict(entry) for entry in self.read_all()]
|
||||
|
||||
def latest(self) -> Optional[ContradictionEntry]:
|
||||
"""Return the most recent log entry if available."""
|
||||
entries = self.read_all()
|
||||
return entries[-1] if entries else None
|
||||
|
||||
def summary(self) -> dict:
|
||||
"""Provide a small summary about the log contents."""
|
||||
entries = self.read_all()
|
||||
return {
|
||||
"count": len(entries),
|
||||
"oldest_ts": entries[0].timestamp if entries else None,
|
||||
"newest_ts": entries[-1].timestamp if entries else None,
|
||||
}
|
||||
|
||||
def __len__(self) -> int: # pragma: no cover - simple delegation
|
||||
return len(self.read_all())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage:
|
||||
|
||||
45
tests/test_contradiction_log.py
Normal file
45
tests/test_contradiction_log.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
from unittest import TestCase
|
||||
from unittest.mock import patch
|
||||
|
||||
from lucidia.contradiction_log import ContradictionLog
|
||||
|
||||
|
||||
class ContradictionLogTest(TestCase):
|
||||
def test_append_and_read_all(self) -> None:
|
||||
with TemporaryDirectory() as tmp:
|
||||
log_path = Path(tmp) / "logs" / "contradictions.jsonl"
|
||||
log = ContradictionLog(str(log_path))
|
||||
|
||||
with patch("lucidia.contradiction_log.time.time", side_effect=[1000.0, 1001.5]):
|
||||
log.append("prompt-one", "reply-one")
|
||||
log.append("prompt-two", "reply-two")
|
||||
|
||||
entries = log.read_all()
|
||||
self.assertEqual(len(entries), 2)
|
||||
self.assertEqual(entries[0].prompt, "prompt-one")
|
||||
self.assertEqual(entries[1].reply, "reply-two")
|
||||
self.assertEqual(entries[0].timestamp, 1000.0)
|
||||
self.assertEqual(entries[1].timestamp, 1001.5)
|
||||
|
||||
def test_summary_and_latest(self) -> None:
|
||||
with TemporaryDirectory() as tmp:
|
||||
log = ContradictionLog(str(Path(tmp) / "nested" / "log.jsonl"))
|
||||
|
||||
with patch("lucidia.contradiction_log.time.time", side_effect=[42.0, 84.0]):
|
||||
log.append("a", "b")
|
||||
log.append("c", "d")
|
||||
|
||||
summary = log.summary()
|
||||
self.assertEqual(summary["count"], 2)
|
||||
self.assertEqual(summary["oldest_ts"], 42.0)
|
||||
self.assertEqual(summary["newest_ts"], 84.0)
|
||||
|
||||
latest = log.latest()
|
||||
assert latest is not None
|
||||
self.assertEqual(latest.prompt, "c")
|
||||
self.assertEqual(latest.reply, "d")
|
||||
|
||||
Reference in New Issue
Block a user