Skip to content

fix(tui-gateway): merge agent output on personality-marker history race - #77860

Open
pierrenode wants to merge 1 commit into
NousResearch:mainfrom
pierrenode:fix/personality-mid-turn-marker-race
Open

fix(tui-gateway): merge agent output on personality-marker history race#77860
pierrenode wants to merge 1 commit into
NousResearch:mainfrom
pierrenode:fix/personality-mid-turn-marker-race

Conversation

@pierrenode

Copy link
Copy Markdown
Contributor

Summary

  • config.set's "personality" key applies immediately regardless of session["running"], unlike "model" (which defers to next-turn-start while a turn is in flight — see the session.get("running") check in config.set's key == "model" branch).
  • A personality change mid-turn (e.g. via the desktop/web settings UI while a response is streaming) appends a marker to session["history"] and bumps history_version — the exact same shape of mutation a model switch makes.
  • The turn-completion mismatch guard in _run_prompt_submit (added by [Bug]: Model switch mid-session triggers history_version mismatch — all subsequent agent output discarded (empty assistant messages in DB) #76870, three days ago) only recognized model-switch markers as a safe, mergeable mutation. A personality-marker-only mismatch fell into the "genuine desync" branch instead: the agent's response for that turn was silently discarded from persisted history (only shown transiently with a "not saved to session history" warning).

Root cause

_apply_personality_to_session (tui_gateway/server.py) has no session.get("running") guard on the config.set RPC path — it calls straight through, appending {"role": "user", "content": marker} and incrementing history_version under session["history_lock"], whether or not a turn is currently in flight.

_run_prompt_submit's post-turn history_version check (introduced by #76870 for the analogous model-switch race) only ever compared against _is_model_switch_marker, so a personality marker landing mid-turn was treated identically to a genuine external desync (/undo, /compress, /retry) — the agent's output for that turn was dropped instead of merged.

Fix

Extend the merge-recovery check to also recognize personality-pivot markers as safe to merge, using the exact content-diff technique #76870/cc04825c5d already established and reviewed for model-switch markers:

  • Added _is_personality_marker() (mirrors _is_model_switch_marker()), matching either the marker's stable "[System: ..." content-prefix (today's shape) or display_kind == "personality_switch" (the structured shape an unrelated open PR, fix(history): stop personality marker from swallowing the next real prompt #74350, would give newly-appended markers — checking both keeps this correct regardless of merge order between the two fixes).
  • _run_prompt_submit's mismatch branch now strips both model-switch and personality markers before the content-diff comparison, and accepts either marker type as the sole safe mutation.

Test plan

  • Added test_prompt_submit_merges_on_personality_marker, mirroring the existing test_prompt_submit_merges_on_model_switch_marker harness. Covers both cases (no prior personality marker, and a prior marker already in the turn-start history) — simulates the race by appending the marker from inside the stub agent's run_conversation(), exactly as a concurrent config.set RPC would mid-turn.
  • Mutation-verified: reverted the tui_gateway/server.py change and confirmed the new test fails with the exact pre-fix symptom (agent output NOT written to session history, 0 assistant messages merged).
  • tests/test_tui_gateway_server.py full suite: 517 passed, 1 pre-existing unrelated failure (test_write_json_serializes_concurrent_writes, a thread-scheduling-timing test — confirmed flaky/pre-existing by re-running it in isolation both with and without this change, unaffected either way).
  • ruff check clean on both changed files.

Competitor check

config.set's "personality" key applies immediately regardless of
session["running"], unlike "model" (which defers to next-turn-start
while a turn is in flight). A personality change mid-turn appends a
history marker and bumps history_version exactly like a model switch
does, but the turn-completion mismatch guard only recognized
model-switch markers as a safe, mergeable mutation (NousResearch#76870) — a
personality-marker mismatch fell into the "genuine desync" branch and
the agent's response for that turn was silently discarded instead of
persisted.

Extend the merge-recovery check in _run_prompt_submit to also
recognize personality-pivot markers (by content-prefix, or by
display_kind == "personality_switch" for forward-compat with the
unrelated NousResearch#74350 marker-persistence fix) as safe to merge, mirroring
the exact technique NousResearch#76870/cc04825c5d already established for
model-switch markers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant