fix: gists show the conversation's real date, not the summarize-run date

Summaries displayed s.created_at (set to now() at summarize time), so every
imported gist read 2026-06-16. Derive the actual session date from the earliest
exchange timestamp (MIN(created_at) per session — the preserved original date,
same source the era rollups use) via a correlated subquery in the summary
readers. New Summary.session_started_at field; chat shows it (falling back to
created_at). No schema change / backfill needed — always correct from source.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-17 04:23:14 +00:00
parent 3b0b808986
commit 2d44457b96
2 changed files with 17 additions and 7 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ SUMMARY_K = 3 # other-session gists
def _summary_note(summaries: list[memory.Summary]) -> Message:
lines = [f"- ({s.created_at[:10]}) {s.content}" for s in summaries]
lines = [f"- ({(s.session_started_at or s.created_at)[:10]}) {s.content}" for s in summaries]
body = "Gist of earlier sessions (compacted — ask if you need specifics):\n" + "\n".join(lines)
return {"role": "system", "content": body}
+16 -6
View File
@@ -122,7 +122,8 @@ class Summary:
session_id: str
content: str
last_exchange_id: int
created_at: str
created_at: str # when the gist was generated
session_started_at: str | None = None # when the conversation actually happened
score: float | None = None
@@ -313,8 +314,9 @@ def store_summary(session_id: str, content: str, last_exchange_id: int) -> None:
def get_summary(session_id: str) -> Summary | None:
conn = _connection()
r = conn.execute(
"SELECT session_id, content, last_exchange_id, created_at FROM summaries "
"WHERE session_id = ?",
"SELECT session_id, content, last_exchange_id, created_at, "
"(SELECT MIN(e.created_at) FROM exchanges e WHERE e.session_id = summaries.session_id) "
"AS started_at FROM summaries WHERE session_id = ?",
(session_id,),
).fetchone()
if r is None:
@@ -324,6 +326,7 @@ def get_summary(session_id: str) -> Summary | None:
content=r["content"],
last_exchange_id=r["last_exchange_id"],
created_at=r["created_at"],
session_started_at=r["started_at"],
)
@@ -343,8 +346,9 @@ def list_summaries() -> list[Summary]:
"""Every session gist (for the profile/era consolidation passes)."""
conn = _connection()
rows = conn.execute(
"SELECT session_id, content, last_exchange_id, created_at FROM summaries "
"ORDER BY created_at ASC"
"SELECT session_id, content, last_exchange_id, created_at, "
"(SELECT MIN(e.created_at) FROM exchanges e WHERE e.session_id = summaries.session_id) "
"AS started_at FROM summaries ORDER BY started_at ASC"
).fetchall()
return [
Summary(
@@ -352,6 +356,7 @@ def list_summaries() -> list[Summary]:
content=r["content"],
last_exchange_id=r["last_exchange_id"],
created_at=r["created_at"],
session_started_at=r["started_at"],
)
for r in rows
]
@@ -560,7 +565,11 @@ def recall_summaries(query: str, k: int = 3, exclude_session: str | None = None)
q = np.asarray(q_vec, dtype=np.float32)
conn = _connection()
sql = "SELECT session_id, content, embedding, last_exchange_id, created_at FROM summaries"
sql = (
"SELECT session_id, content, embedding, last_exchange_id, created_at, "
"(SELECT MIN(e.created_at) FROM exchanges e WHERE e.session_id = summaries.session_id) "
"AS started_at FROM summaries"
)
params: tuple = ()
if exclude_session is not None:
sql += " WHERE session_id != ?"
@@ -580,6 +589,7 @@ def recall_summaries(query: str, k: int = 3, exclude_session: str | None = None)
content=rows[i]["content"],
last_exchange_id=rows[i]["last_exchange_id"],
created_at=rows[i]["created_at"],
session_started_at=rows[i]["started_at"],
score=float(scores[i]),
)
for i in top_idx