feat: redesign chat transcript + fix streaming/persistence lifecycle — v0.50.70 (PR #587 by @aronprins)

Redesign chat transcript + fix streaming/persistence lifecycle — v0.50.70

Squash-merges PR #587 by @aronprins (Aron Prins). Full credit to @aronprins for all feature and fix work.

Transcript redesign: unified --msg-rail/--msg-max CSS variables, user turns as tinted cards, thinking cards as bordered panels, error card treatment, day-change separators, composer fade.

Approval/clarify as composer flyouts: cards slide up from behind composer top, overflow:hidden + translateY clip prevents travel visibility, focus({preventScroll:true}).

Streaming lifecycle: DOM order user→thinking→tool cards→response, no mid-stream jump. Live tool cards inserted before [data-live-assistant].

Persistence: reasoning attached before s.save(), _restore_reasoning_metadata on reload, role=tool rows preserved in S.messages, CLI-session tool-result fallback.

Workspace panel FOUC fix: [data-workspace-panel] set at parse time.

Docs: docs/ui-ux/index.html + two-stage-proposal.html.

Maintainer additions (433b867): CHANGELOG v0.50.70, version badge, usage badge loop simplification.

Reviewed and approved by @nesquena (independent review). 1361 tests passing.
This commit is contained in:
Aron Prins
2026-04-16 23:04:42 +02:00
committed by GitHub
parent 25d38a467a
commit 9a3dc10d93
20 changed files with 2770 additions and 469 deletions

View File

@@ -428,3 +428,29 @@ def test_rendermessages_reads_reasoning_from_messages():
# Specifically, the fallback that reads from top-level m.reasoning field
assert 'thinkingText=m.reasoning' in src.replace(' ', ''), \
"thinkingText=m.reasoning assignment not found in ui.js renderMessages"
def test_streaming_restores_prior_reasoning_metadata_after_followup():
"""Previous-turn thinking must survive later turns.
The provider-facing history strips WebUI-only `reasoning` fields, so the
streaming path must merge that metadata back onto the returned message
history before saving the session, including reinserting dropped
reasoning-only assistant segments.
"""
src = (REPO / 'api' / 'streaming.py').read_text()
assert "def _restore_reasoning_metadata(" in src, \
"streaming.py must define a helper to restore prior reasoning metadata"
assert "s.messages = _restore_reasoning_metadata(" in src, \
"streaming.py must merge prior reasoning metadata back after run_conversation()"
assert "updated_messages.insert(safe_pos, copy.deepcopy(prev_msg))" in src, \
"streaming.py must reinsert dropped reasoning-only assistant messages"
def test_routes_restores_prior_reasoning_metadata_after_followup():
"""The non-streaming route path must preserve prior reasoning metadata too."""
src = (REPO / 'api' / 'routes.py').read_text()
assert "_restore_reasoning_metadata" in src, \
"routes.py must import reasoning metadata restoration helper"
assert 's.messages = _restore_reasoning_metadata(' in src, \
"routes.py must merge prior reasoning metadata back after run_conversation()"