fix(chat): keep live reasoning on one renderer path

Clean rebase of rodboev's #5773 (rebase-first).

Co-authored-by: rodboev <rodboev@users.noreply.github.com>
This commit is contained in:
nesquena-hermes
2026-07-08 07:49:04 +00:00
parent 07b9708cde
commit 0872800a88
4 changed files with 47 additions and 5 deletions
+4 -2
View File
@@ -5024,8 +5024,10 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){
if(d.text&&S.session&&S.session.session_id===activeSid) _completeAutomaticCompressionOnLiveProgress(activeSid);
syncInflightAssistantMessage();
if(text&&S.session&&S.session.session_id===activeSid){
_upsertAnchorReasoning(_liveThinkingText());
_updateLiveThinkingCard(_liveThinkingText());
const liveThinkingText=_liveThinkingText();
if(!_upsertAnchorReasoning(liveThinkingText)){
_updateLiveThinkingCard(liveThinkingText);
}
}
});
+6 -2
View File
@@ -931,8 +931,12 @@ def test_messages_js_supports_live_reasoning_and_tool_completion(cleanup_test_se
"messages.js must listen for live reasoning SSE events"
assert "liveReasoningText += text" in src, \
"live reasoning SSE events must update the active Worklog Thinking Card text"
assert "_updateLiveThinkingCard(_liveThinkingText())" in src, \
"live reasoning SSE events must refresh the current segment's Worklog Thinking Card"
assert "const liveThinkingText=_liveThinkingText();" in src, \
"live reasoning SSE events must compute the current segment's Worklog Thinking Card text once"
assert "if(!_upsertAnchorReasoning(liveThinkingText))" in src, \
"live reasoning SSE events must prefer the anchor renderer before falling back"
assert "_updateLiveThinkingCard(liveThinkingText)" in src, \
"live reasoning SSE events must keep the current segment's Worklog Thinking Card as fallback"
assert "source.addEventListener('tool_complete'" in src or 'source.addEventListener("tool_complete"' in src, \
"messages.js must listen for live tool completion SSE events"
assert "function _parseStreamState()" in src, \
@@ -1306,7 +1306,9 @@ def test_slice6_live_shadow_feed_wires_anchor_scene_for_visible_order_handoff():
assert "_upsertAnchorProcessProse(displayText" in src
reasoning_body = _event_listener_body(src, "reasoning")
assert "_applyToAnchor" not in reasoning_body
assert "_upsertAnchorReasoning(_liveThinkingText())" in reasoning_body
assert "const liveThinkingText=_liveThinkingText();" in reasoning_body
assert "if(!_upsertAnchorReasoning(liveThinkingText))" in reasoning_body
assert "_updateLiveThinkingCard(liveThinkingText)" in reasoning_body
assert "function _flushReasoningToAnchor()" in src
assert "_upsertAnchorReasoning(reasoningText" in src
assert "`live-reasoning:${streamId}:final`" in src
+34
View File
@@ -670,6 +670,40 @@ class TestToolCallGroupingStatic:
"Tool starts must not split consecutive tools into one-tool Activity rows."
)
def test_reasoning_stream_uses_one_live_renderer_path(self):
reasoning_match = re.search(
r"source\.addEventListener\('reasoning',e=>\{(.*?)\n\s*\}\);",
MESSAGES_JS,
re.S,
)
assert reasoning_match, "reasoning listener not found"
reasoning_fn = reasoning_match.group(1)
render_live_thinking_fn = _function_body(MESSAGES_JS, "_renderLiveThinking")
assert reasoning_fn.count("_liveThinkingText()") == 1, (
"_liveThinkingText() should be computed once inside the active-session branch."
)
assert "const liveThinkingText=_liveThinkingText();" in reasoning_fn, (
"Reasoning SSE updates should cache the live thinking text before routing."
)
assert "_upsertAnchorReasoning(liveThinkingText)" in reasoning_fn, (
"Anchor reasoning must remain the primary renderer path."
)
assert reasoning_fn.index("_upsertAnchorReasoning(liveThinkingText)") < reasoning_fn.index(
"_updateLiveThinkingCard(liveThinkingText)"
), (
"The legacy thinking card should only run after anchor upsert fails."
)
assert "if(!_upsertAnchorReasoning(liveThinkingText)){" in reasoning_fn, (
"The legacy thinking card should be a falsy-anchor fallback."
)
assert reasoning_fn.count("_updateLiveThinkingCard(liveThinkingText)") == 1, (
"Reasoning SSE updates should call the live thinking card only in fallback."
)
assert "_updateLiveThinkingCard(" in render_live_thinking_fn, (
"Inline parsed thinking still needs the live thinking card renderer."
)
def test_live_thinking_card_is_segment_scoped_not_global_singleton(self):
live_thinking_fn = _function_body(UI_JS, "appendThinking")
placement_fn = _function_body(MESSAGES_JS, "_liveThinkingPlacement")