feat: post-turn state-update pass per present entity
This commit is contained in:
@@ -24,6 +24,45 @@ def append_event(conn: Connection, *, kind: str, payload: dict[str, Any], branch
|
||||
return cur.lastrowid
|
||||
|
||||
|
||||
def append_and_apply(
|
||||
conn: Connection,
|
||||
*,
|
||||
kind: str,
|
||||
payload: dict[str, Any],
|
||||
branch_id: int = 1,
|
||||
) -> int:
|
||||
"""Append an event AND immediately apply just that event's handler.
|
||||
|
||||
Calling :func:`chat.eventlog.projector.project` after an append
|
||||
re-runs every prior event, which is fine for idempotent inserts but
|
||||
catastrophic for delta-shaped events like ``edge_update`` whose
|
||||
handler is *not* replay-safe (each pass would re-add the same
|
||||
``affinity_delta``). This helper runs only the brand-new event
|
||||
through the registered handler, leaving prior state untouched.
|
||||
|
||||
No-ops cleanly when ``kind`` has no registered handler — useful for
|
||||
transcript-only events like ``user_turn`` / ``assistant_turn`` where
|
||||
callers may swap ``append_event`` for ``append_and_apply`` without
|
||||
side effects.
|
||||
"""
|
||||
# Local import to avoid a circular dependency at module import: the
|
||||
# projector imports from .log to define ``Event``.
|
||||
from chat.eventlog.projector import apply_event
|
||||
|
||||
eid = append_event(conn, kind=kind, payload=payload, branch_id=branch_id)
|
||||
event = Event(
|
||||
id=eid,
|
||||
branch_id=branch_id,
|
||||
ts="",
|
||||
kind=kind,
|
||||
payload=payload,
|
||||
superseded_by=None,
|
||||
hidden=False,
|
||||
)
|
||||
apply_event(conn, event)
|
||||
return eid
|
||||
|
||||
|
||||
def read_events(conn: Connection, branch_id: int = 1, after_id: int = 0) -> Iterator[Event]:
|
||||
cur = conn.execute(
|
||||
"SELECT id, branch_id, ts, kind, payload_json, superseded_by, hidden "
|
||||
|
||||
Reference in New Issue
Block a user