[eric] agents: an invisible thinking pill no longer breaks the repeat-card dedup

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014wtspwSFzZmjCx9UNPAorQ
This commit is contained in:
ciregenz
2026-08-20 12:32:14 -07:00
co-authored by Claude Opus 5
parent 6f313a445c
commit 7c04c755ae
3 changed files with 43 additions and 2 deletions
@@ -34,6 +34,12 @@ logger = logging.getLogger(__name__)
@typechecked
def p_renders_as_nothing(msg: Message) -> bool:
"""An empty thinking pill occupies the tail while showing the user nothing, which silently broke the dedup below (live drill 2026-08-20: three identical cards)."""
return msg.role == "thinking" and not str(msg.content or "").strip()
@typechecked
def absorb_repeat_card(session: AgentSession, error_msg: Message) -> None:
"""Append the error card, unless the branch tail is already the IDENTICAL card with nothing
@@ -47,7 +53,8 @@ def absorb_repeat_card(session: AgentSession, error_msg: Message) -> None:
because each retry's hidden prompt had displaced the previous card from the tail."""
p_tail = [m for m in session.messages
if getattr(m, "branch_id", None) in (None, session.active_branch_id)
and not getattr(m, "hidden", False)]
and not getattr(m, "hidden", False)
and not p_renders_as_nothing(m)]
if p_tail and p_tail[-1].role == "system" and p_tail[-1].content == error_msg.content:
error_msg.id = p_tail[-1].id
p_tail[-1].timestamp = error_msg.timestamp
@@ -220,7 +220,10 @@ async def handle_assistant_message(
content=p_copy,
branch_id=session.active_branch_id,
)
session.messages.append(p_card)
# A retry ladder re-failing the same way must bump one card, not stack clones; the live
# drill produced three before this line existed.
from backend.apps.agents.manager.run.handle_run_error import absorb_repeat_card
absorb_repeat_card(session, p_card)
logger.warning(
f"Agent {session_id}: provider returned {p_provider_error.kind} "
f"(status={p_provider_error.status}, lane={p_provider_error.lane}) as assistant "
+31
View File
@@ -78,3 +78,34 @@ def test_a_real_user_message_still_earns_a_fresh_card():
shown = [m for m in s.messages if m.role == "system"]
assert len(shown) == 2, "each real ask gets its own honest answer"
def test_an_empty_thinking_pill_does_not_break_the_dedup():
"""Found by the live provider-error drill 2026-08-20, invisible to every unit test here.
Each retry leaves a non-hidden `thinking` message with empty content sitting in the tail. It
renders as nothing, but it displaced the previous card from the tail scan, so a re-failing
ladder stacked three identical cards on screen while this suite stayed green.
"""
s = AgentSession(name="t", model="sonnet")
first = p_card("Lost the connection to the model.")
absorb_repeat_card(s, first)
s.messages.append(Message(role="thinking", content="", branch_id="main"))
repeat = p_card("Lost the connection to the model.")
absorb_repeat_card(s, repeat)
p_cards = [m for m in s.messages if m.role == "system"]
assert len(p_cards) == 1, "an invisible pill must not earn the user a duplicate card"
assert repeat.id == first.id
def test_a_thinking_pill_with_real_content_still_breaks_the_dedup():
"""NEGATIVE CONTROL. Only the EMPTY pill is invisible; real thinking is content the user saw,
so a card after it is genuinely new and must not be absorbed into the older one."""
s = AgentSession(name="t", model="sonnet")
first = p_card("Lost the connection to the model.")
absorb_repeat_card(s, first)
s.messages.append(Message(role="thinking", content="Let me try that again.", branch_id="main"))
repeat = p_card("Lost the connection to the model.")
absorb_repeat_card(s, repeat)
p_cards = [m for m in s.messages if m.role == "system"]
assert len(p_cards) == 2, "visible thinking separates the two failures"