mirror of
https://github.com/blackboxprogramming/remember.git
synced 2026-03-17 07:57:26 -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
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
from dataclasses import dataclass, asdict
|
from dataclasses import dataclass, asdict
|
||||||
from typing import List
|
from pathlib import Path
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -22,17 +24,19 @@ class ContradictionEntry:
|
|||||||
|
|
||||||
class ContradictionLog:
|
class ContradictionLog:
|
||||||
def __init__(self, path: str = "contradiction_log.jsonl") -> None:
|
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:
|
def append(self, prompt: str, reply: str) -> None:
|
||||||
entry = ContradictionEntry(time.time(), prompt, reply)
|
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")
|
f.write(json.dumps(asdict(entry)) + "\n")
|
||||||
|
|
||||||
def read_all(self) -> List[ContradictionEntry]:
|
def read_all(self) -> List[ContradictionEntry]:
|
||||||
entries: List[ContradictionEntry] = []
|
entries: List[ContradictionEntry] = []
|
||||||
try:
|
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:
|
for line in f:
|
||||||
data = json.loads(line.strip())
|
data = json.loads(line.strip())
|
||||||
entries.append(ContradictionEntry(**data))
|
entries.append(ContradictionEntry(**data))
|
||||||
@@ -40,6 +44,27 @@ class ContradictionLog:
|
|||||||
pass
|
pass
|
||||||
return entries
|
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__":
|
if __name__ == "__main__":
|
||||||
# Example usage:
|
# 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