fix: keep assistant-only stream deltas on current turn

This commit is contained in:
Michael Lam
2026-05-06 22:32:29 -07:00
committed by nesquena-hermes
parent 34726c3356
commit 048f1fa24e
3 changed files with 54 additions and 0 deletions

View File

@@ -1516,6 +1516,33 @@ def _merge_display_messages_after_agent_result(previous_display, previous_contex
merged = previous_display[:]
seen = {_message_identity(m) for m in merged}
current_user_key = _message_identity({'role': 'user', 'content': msg_text})
current_user_in_candidates = any(
_message_identity(m) == current_user_key for m in candidates
)
current_user_already_checkpointed = bool(
merged and _message_identity(merged[-1]) == current_user_key
)
if (
current_user_key is not None
and not current_user_in_candidates
and not current_user_already_checkpointed
and any(
isinstance(m, dict) and m.get('role') in ('assistant', 'tool')
for m in candidates
)
):
# Some provider retry/fallback paths can return an assistant/tool delta
# without echoing the current user turn. In deferred session-save mode
# the prompt exists only in pending_user_message, so appending that delta
# directly would make the assistant bubble appear attached to the prior
# exchange and then clear the pending prompt. Materialize the current
# turn at the transcript boundary before the assistant/tool response.
current_user_msg = {'role': 'user', 'content': msg_text}
insert_at = 0
while insert_at < len(candidates) and _is_context_compression_marker(candidates[insert_at]):
insert_at += 1
candidates = candidates[:insert_at] + [current_user_msg] + candidates[insert_at:]
for msg in candidates:
key = _message_identity(msg)
if (

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -130,3 +130,30 @@ def test_eager_checkpointed_user_is_not_duplicated_after_agent_result():
msg_text="repeat me",
)
assert [m["role"] for m in merged] == ["user", "assistant"]
def test_deferred_turn_is_materialized_when_agent_returns_assistant_only_delta():
merged = streaming._merge_display_messages_after_agent_result(
previous_display=[
{"role": "user", "content": "older prompt"},
{"role": "assistant", "content": "older answer"},
],
previous_context=[
{"role": "user", "content": "older prompt"},
{"role": "assistant", "content": "older answer"},
],
result_messages=[
{"role": "user", "content": "older prompt"},
{"role": "assistant", "content": "older answer"},
{"role": "assistant", "content": "current answer"},
],
msg_text="latest prompt",
)
assert [m["role"] for m in merged] == [
"user",
"assistant",
"user",
"assistant",
]
assert [m["content"] for m in merged[-2:]] == ["latest prompt", "current answer"]