Release v0.51.347 — Release LK (streaming & render reliability cluster #3892 #3898 #3885 #3882 #3868) (#3902)
* stage v0.51.347: render/stream cluster (#3892 #3898 #3885 #3882 #3868) + 2 Opus SHOULD-FIX * stage v0.51.347: trim #3885 error-guard comment to fit diagnostic-test window * Stamp v0.51.347 — Release LK (streaming & render reliability cluster) * Remove stray uv.lock accidentally staged (not part of any cluster PR) --------- Co-authored-by: nesquena-hermes <[email protected]>
This commit is contained in:
1 parent
aa5cd6e8ff
commit
e8d71a2fb8
24 files changed
+1067
-205
No files matched your search
@@ -0,0 +1,121 @@
|
||||
"""Regression coverage for stream-end recovery ordering.
|
||||
|
||||
#3877-style recovery relies on one subtle path:
|
||||
when `stream_end` arrives while the active live assistant row is still
|
||||
present, cleanup should be deferred briefly to allow pending final SSE updates to
|
||||
settle, then performed through the shared terminal recovery helper.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
MESSAGES_JS = (REPO_ROOT / "static" / "messages.js").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def _event_block(event_name: str) -> str:
|
||||
marker = f"source.addEventListener('{event_name}'"
|
||||
start = MESSAGES_JS.find(marker)
|
||||
assert start >= 0, f"missing {event_name} listener"
|
||||
brace = MESSAGES_JS.find("{", start)
|
||||
assert brace >= 0, f"missing {event_name} listener body"
|
||||
depth = 0
|
||||
i = brace
|
||||
while i < len(MESSAGES_JS):
|
||||
if MESSAGES_JS[i] == "{":
|
||||
depth += 1
|
||||
elif MESSAGES_JS[i] == "}":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
return MESSAGES_JS[brace : i + 1]
|
||||
i += 1
|
||||
raise AssertionError(f"unclosed {event_name} listener body")
|
||||
|
||||
|
||||
def _function_body(name: str) -> str:
|
||||
marker = f"async function {name}("
|
||||
start = MESSAGES_JS.find(marker)
|
||||
if start < 0:
|
||||
marker = f"function {name}("
|
||||
start = MESSAGES_JS.find(marker)
|
||||
assert start >= 0, f"missing function: {name}"
|
||||
brace = MESSAGES_JS.find("{", start)
|
||||
assert brace >= 0, f"missing {name} body"
|
||||
depth = 0
|
||||
i = brace
|
||||
while i < len(MESSAGES_JS):
|
||||
if MESSAGES_JS[i] == "{":
|
||||
depth += 1
|
||||
elif MESSAGES_JS[i] == "}":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
return MESSAGES_JS[brace : i + 1]
|
||||
i += 1
|
||||
raise AssertionError(f"unclosed function body: {name}")
|
||||
|
||||
|
||||
def test_stream_end_defers_settlement_when_live_assistant_still_present():
|
||||
body = _event_block("stream_end")
|
||||
assert "if(S.activeStreamId===streamId && _liveStreamEndScenePresent())" in body, (
|
||||
"stream_end should defer terminal cleanup while active live scene content is still present"
|
||||
)
|
||||
assert "_scheduleStreamEndRecovery(source);" in body, (
|
||||
"stream_end should schedule the deferred recovery timer before returning"
|
||||
)
|
||||
assert "_scheduleStreamEndRecovery(source)" in body, (
|
||||
"stream_end must delegate deferred cleanup to helper"
|
||||
)
|
||||
|
||||
|
||||
def test_stream_end_fallback_does_not_finalize_when_session_is_still_active():
|
||||
body = _event_block("stream_end")
|
||||
assert "const status=await _restoreSettledSession(source,{status:true});" in body
|
||||
assert "if(status==='active'&&S.activeStreamId===streamId)" in body
|
||||
assert "_scheduleStreamEndRecovery(source,200);" in body
|
||||
assert "_finalizeStreamEndFallback(source);" in body
|
||||
|
||||
|
||||
def test_stream_end_recovery_helper_retries_while_session_is_still_active():
|
||||
fn = _function_body("_runStreamEndRecovery")
|
||||
assert "if(_streamFinalized || _terminalStateReached || !_pendingStreamEndRecovery)" in fn
|
||||
assert "_restoreSettledSession(source,{status:true})" in fn
|
||||
assert "if(status==='active'&&_streamEndRecoveryAttempts<10)" in fn
|
||||
assert "_scheduleStreamEndRecovery(source,200);" in fn
|
||||
assert "_finalizeStreamEndFallback(source);" in fn
|
||||
|
||||
|
||||
def test_stream_end_fallback_helper_clears_owner_state_before_closing():
|
||||
fn = _function_body("_finalizeStreamEndFallback")
|
||||
assert "_terminalStateReached=true;" in fn
|
||||
assert "_streamFinalized=true;" in fn
|
||||
assert "_clearOwnerInflightState();" in fn
|
||||
assert "_clearApprovalForOwner();" in fn
|
||||
assert "_clearClarifyForOwner('terminal');" in fn
|
||||
assert "renderMessages({preserveScroll:true});" in fn
|
||||
assert "_setActivePaneIdleIfOwner();" in fn
|
||||
assert "_closeSource(source)" in fn
|
||||
|
||||
|
||||
def test_stream_end_live_scene_detection_includes_empty_text_activity():
|
||||
fn = _function_body("_liveStreamEndScenePresent")
|
||||
assert "if(assistantText||assistantRow) return true;" in fn
|
||||
assert "liveReasoningText||reasoningText" in fn
|
||||
assert "inflight.toolCalls.length" in fn
|
||||
assert "data-live-worklog-shell" in fn
|
||||
assert "data-thinking-active" in fn
|
||||
|
||||
|
||||
def test_restore_settled_session_can_report_active_pending_status():
|
||||
fn = _function_body("_restoreSettledSession")
|
||||
assert "async function _restoreSettledSession(source, options=null)" in MESSAGES_JS
|
||||
assert "arguments[1]" not in fn
|
||||
assert "const returnStatus=!!(options&&options.status);" in fn
|
||||
assert "return returnStatus?'active':false;" in fn
|
||||
assert "return returnStatus?'restored':true;" in fn
|
||||
|
||||
|
||||
def test_stream_end_recovery_state_is_cleared_on_done_and_terminal_events():
|
||||
assert "_clearStreamEndRecovery();" in _event_block("done")
|
||||
assert "_clearStreamEndRecovery();" in _event_block("stream_end")
|
||||
assert "_clearStreamEndRecovery();" in _event_block("cancel")
|
||||
assert "_clearStreamEndRecovery();" in _event_block("apperror")
|
||||
Reference in new issue
Block a user