fix(tui): session.history withholds the row_id message.react needs - #74701
fix(tui): session.history withholds the row_id message.react needs#74701Drexuxux wants to merge 1 commit into
Conversation
session.history is a renderer-facing projection - it returns _history_to_messages(history), and that helper forwards `row_id` only when the history dicts carry `_row_id` (tui_gateway/server.py). 1af8839 made `_row_id` opt-in (include_row_ids=True) so model-facing consumers - ACP restore, export, inspection - keep the historical transcript shape. Every other display projection was updated to opt in (server.py resume/display paths, methods_session.py session.resume); session.history was missed, so it now hands the renderer a transcript with no durable ids at all. message.react addresses messages by exactly that id. Its only fallback, newest_role, resolves to the newest row of a role - so with the ids gone, every message except the latest becomes unreactable. Measured on a 4-message transcript: 0/4 messages addressable via session.history, 4/4 via the sibling projections. Opt in, matching the other display projections. The post-undo live-replay reload deliberately stays opt-out.
|
Thanks—this is a narrow, verified correction. Current main's The proposed opt-in targets that exact display projection. The added tests exercise persisted rows and verify both durable-ID ordering and addressing an older row, while retaining the default no-row-ID model-facing projection. Automated hermes-sweeper review. |
What
session.historyhands the renderer a transcript with no durable message ids, so the new reactions feature can only ever react to the newest message.session.historyis a renderer-facing projection — it returns_history_to_messages(history), and that helper forwardsrow_idonly when the history dicts carry_row_id:1af883913made_row_idopt-in (include_row_ids=True) so model-facing consumers — ACP restore, export, inspection — keep the historical transcript shape. That was the right call, and every other display projection was updated to opt in (server.pyresume/display paths,session.resumeinmethods_session.py).session.historywas missed.message.reactaddresses messages by exactly that id, and its docstring says so: "row_idis the durablemessages.idforwarded by_history_to_messages— the renderer's own message ids are ephemeral." Its only fallback,newest_role, resolves to the newest row of a role — so with the ids gone, every message except the latest becomes unreactable.Measured on a 4-message transcript:
The write path is fine —
set_message_reactionaccepts the older row once you can name it. Only the projection was withholding the id.Fix
Pass
include_row_ids=Trueinsession.history, matching the other display projections. The post-undo live-replay reload (methods_tools.py) deliberately stays opt-out so replay history keeps its historical shape.Tests
tests/tui_gateway/test_session_history_row_ids.py— 4 tests; the 3 behavioral ones fail without the fix (KeyError: 'row_id'), the 4th guards the other half of the split:row_idmessages.idvalues, in ordernewest_rolecan reach_row_idSuite unaffected:
794 passedacrosstests/tui_gateway/+tests/test_tui_gateway_server.py(the 2 failures there —test_entry_import_off_main_thread,test_append_log_record_single_write_lines— reproduce identically onmainwithout this change).