Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
"""Regression (#68454): /new, /resume, /branch must not re-append cold-resumed
|
||||
transcript rows when flushing before session rotation.
|
||||
|
||||
Sibling of #68196 / #68205 (preflight compression path). Cold resume loads
|
||||
plain dicts without ``_DB_PERSISTED_MARKER``. If the user rotates immediately
|
||||
via /new, /resume, or /branch, the old-session flush must pass
|
||||
``conversation_history=`` so identity skip treats the loaded prefix as durable.
|
||||
|
||||
These tests bind the real ``AIAgent._flush_messages_to_session_db`` methods onto
|
||||
a lightweight stand-in so construction never hits network model-metadata
|
||||
lookups (offline CI / hung OpenRouter).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
from hermes_state import SessionDB
|
||||
from run_agent import AIAgent
|
||||
|
||||
|
||||
def _make_flush_agent(db: SessionDB, session_id: str):
|
||||
"""Minimal agent shell that owns the real flush implementation."""
|
||||
agent = SimpleNamespace(
|
||||
_session_db=db,
|
||||
_session_db_created=True,
|
||||
_persist_disabled=False,
|
||||
session_id=session_id,
|
||||
_session_persist_lock=None,
|
||||
_flushed_db_message_ids=set(),
|
||||
_flushed_db_message_session_id=None,
|
||||
_last_flushed_db_idx=0,
|
||||
_persist_user_message_idx=None,
|
||||
_persist_user_message_override=None,
|
||||
_persist_user_message_timestamp=None,
|
||||
_pending_cli_user_message=None,
|
||||
)
|
||||
agent._ensure_db_session = lambda: None
|
||||
agent._flush_messages_to_session_db = (
|
||||
AIAgent._flush_messages_to_session_db.__get__(agent, AIAgent)
|
||||
)
|
||||
agent._flush_messages_to_session_db_unlocked = (
|
||||
AIAgent._flush_messages_to_session_db_unlocked.__get__(agent, AIAgent)
|
||||
)
|
||||
return agent
|
||||
|
||||
|
||||
def _contents(rows):
|
||||
return [r.get("content") for r in rows]
|
||||
|
||||
|
||||
def test_rotation_flush_without_history_boundary_is_safe(tmp_path: Path) -> None:
|
||||
"""Bare flush of cold-resumed rows must NOT double-write (#68454 → #92231).
|
||||
|
||||
Historically this was a control test asserting the double-write: loaded
|
||||
rows carried no ``_DB_PERSISTED_MARKER``, so a flush without
|
||||
``conversation_history=`` re-appended the whole transcript. Since #92231
|
||||
the loaders stamp the marker at row-materialization time, so even the
|
||||
"wrong" call shape (no history boundary) is idempotent.
|
||||
"""
|
||||
db = SessionDB(db_path=tmp_path / "state.db")
|
||||
sid = "COLD_ROTATE_DUP"
|
||||
db.create_session(sid, source="cli")
|
||||
db.append_message(sid, "user", "persisted question")
|
||||
db.append_message(sid, "assistant", "persisted answer")
|
||||
|
||||
loaded = db.get_messages_as_conversation(sid)
|
||||
agent = _make_flush_agent(db, sid)
|
||||
agent._flush_messages_to_session_db(loaded) # missing conversation_history=
|
||||
|
||||
rows = db.get_messages_as_conversation(sid, include_inactive=True)
|
||||
assert _contents(rows) == ["persisted question", "persisted answer"]
|
||||
|
||||
|
||||
def test_rotation_flush_with_history_boundary_is_noop(tmp_path: Path) -> None:
|
||||
"""Fix shape used by /new, /resume, /branch: pass conversation_history=self list."""
|
||||
db = SessionDB(db_path=tmp_path / "state.db")
|
||||
sid = "COLD_ROTATE_OK"
|
||||
db.create_session(sid, source="cli")
|
||||
db.append_message(sid, "user", "persisted question")
|
||||
db.append_message(sid, "assistant", "persisted answer")
|
||||
|
||||
loaded = db.get_messages_as_conversation(sid)
|
||||
agent = _make_flush_agent(db, sid)
|
||||
agent._flush_messages_to_session_db(
|
||||
loaded,
|
||||
conversation_history=loaded,
|
||||
)
|
||||
|
||||
rows = db.get_messages_as_conversation(sid, include_inactive=True)
|
||||
assert _contents(rows) == ["persisted question", "persisted answer"]
|
||||
|
||||
|
||||
def test_rotation_flush_writes_only_new_tail(tmp_path: Path) -> None:
|
||||
"""If a turn added messages after cold resume, only the tail is written."""
|
||||
db = SessionDB(db_path=tmp_path / "state.db")
|
||||
sid = "COLD_ROTATE_TAIL"
|
||||
db.create_session(sid, source="cli")
|
||||
db.append_message(sid, "user", "persisted question")
|
||||
db.append_message(sid, "assistant", "persisted answer")
|
||||
|
||||
loaded = db.get_messages_as_conversation(sid)
|
||||
live = [*loaded, {"role": "user", "content": "new unpersisted turn"}]
|
||||
agent = _make_flush_agent(db, sid)
|
||||
agent._flush_messages_to_session_db(
|
||||
live,
|
||||
conversation_history=loaded,
|
||||
)
|
||||
|
||||
rows = db.get_messages_as_conversation(sid, include_inactive=True)
|
||||
assert _contents(rows) == [
|
||||
"persisted question",
|
||||
"persisted answer",
|
||||
"new unpersisted turn",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user