fix(compression): preserve steer display identity
(cherry picked from commit a8570878bc848a42cc8029fc45219a57e76be4c4)
This commit is contained in:
@@ -77,11 +77,13 @@ def _active_assistant_row(conn: sqlite3.Connection, session_id: str, row_id: int
|
||||
|
||||
|
||||
def sync_flushed_message_markers(batch_msgs: List[Dict[str, Any]], batch_rows: List[Dict[str, Any]]) -> None:
|
||||
"""Stamp _DB_PERSISTED_MARKER and sync canonical row ID / content onto live dicts after commit."""
|
||||
"""Stamp _DB_PERSISTED_MARKER and sync canonical durable fields onto live dicts after commit."""
|
||||
for written, row in zip(batch_msgs, batch_rows):
|
||||
written[_DB_PERSISTED_MARKER] = True
|
||||
if isinstance(row.get("_row_id"), int):
|
||||
written["_row_id"] = row["_row_id"]
|
||||
if isinstance(row.get("timestamp"), (int, float)):
|
||||
written["timestamp"] = row["timestamp"]
|
||||
if "_canonical_content" in row:
|
||||
written["content"] = row["_canonical_content"]
|
||||
|
||||
|
||||
@@ -515,6 +515,11 @@ class SessionMessagesMixin:
|
||||
message_timestamp = _coerce_timestamp(msg.get("timestamp"), now_ts)
|
||||
cur = conn.execute(_INSERT_MESSAGE_SQL, self._message_row_params(
|
||||
session_id, role, msg, tool_calls, message_timestamp, keep_reasoning=role == "assistant"))
|
||||
# Keep the caller's live row aligned with the durable identity. Rows created without an explicit
|
||||
# timestamp (notably mid-turn steers) may be carried through several compaction generations; if
|
||||
# the generated timestamp exists only in SQLite, every copy receives a new identity and renders
|
||||
# as another logical message.
|
||||
msg["timestamp"] = message_timestamp
|
||||
if cur.lastrowid is not None:
|
||||
msg["_row_id"] = cur.lastrowid
|
||||
inserted += 1
|
||||
|
||||
40
tests/agent/test_steer_compaction_persistence.py
Normal file
40
tests/agent/test_steer_compaction_persistence.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""Regression coverage for steer display identity across compactions (#117137)."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from agent.prompt_builder import steer_user_row
|
||||
from hermes_state import SessionDB
|
||||
from run_agent import AIAgent
|
||||
|
||||
|
||||
def test_flushed_steer_keeps_one_display_identity_across_compactions(tmp_path):
|
||||
db = SessionDB(tmp_path / "state.db")
|
||||
session_id = "steer-compaction"
|
||||
with patch.dict("os.environ", {"OPENROUTER_API_KEY": "test-key"}):
|
||||
agent = AIAgent(
|
||||
api_key="test-key",
|
||||
base_url="https://openrouter.ai/api/v1",
|
||||
model="test/model",
|
||||
quiet_mode=True,
|
||||
session_db=db,
|
||||
session_id=session_id,
|
||||
skip_context_files=True,
|
||||
skip_memory=True,
|
||||
)
|
||||
agent._ensure_db_session()
|
||||
steer = steer_user_row("focus on the persistence failure")
|
||||
|
||||
agent._flush_messages_to_session_db([steer], [])
|
||||
|
||||
durable_timestamp = db.get_messages(session_id)[0]["timestamp"]
|
||||
assert steer["timestamp"] == durable_timestamp
|
||||
|
||||
for _ in range(2):
|
||||
db.archive_and_compact(session_id, [dict(steer)])
|
||||
|
||||
physical = db.get_messages(session_id, include_inactive=True)
|
||||
assert len([row for row in physical if row["display_kind"] == "steer"]) == 3
|
||||
visible = db.get_messages(session_id, include_compacted=True)
|
||||
assert [(row["display_kind"], row["content"]) for row in visible] == [
|
||||
("steer", steer["content"]),
|
||||
]
|
||||
Reference in New Issue
Block a user