stage #4689 (franksong2702) v3: suppress duplicate live process echoes — authoritative head 14e8fba6 (#4697)
Module-level _compact_for_echo_compare (strips ALL whitespace, \s+ -> '') so _is_visible_output_echo's endswith() suffix-match detects interim_assistant prose that only differs from visible token prose by line-break/paragraph formatting. Hoisted to module scope (importable) + behavior-based test (real token vs interim text equality). Codex SAFE (exact suffix match, not substring). 103 echo/journal tests. Co-authored-by: nesquena-hermes <agent@nesquena-hermes> Co-authored-by: franksong2702 <franksong2702@users.noreply.github.com>
This commit is contained in:
3 files changed
+20
-3
No files matched your search
@@ -3,6 +3,12 @@
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [v0.51.585] — 2026-06-22 — Release UR (suppress duplicate live process echoes)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Live progress text no longer appears twice during streaming.** When the same process prose surfaced through both the visible assistant stream and the live Thinking/interim updates (differing only by paragraph or line-break formatting), it could render duplicated. The server-side visible-output echo detection now ignores all whitespace when comparing, so an `interim_assistant` update that only reformats already-visible token prose is correctly recognized as an echo and suppressed at the source. Thanks @franksong2702. (#4689)
|
||||||
|
|
||||||
## [v0.51.584] — 2026-06-22 — Release UQ (freeze /api/sessions cache during streaming)
|
## [v0.51.584] — 2026-06-22 — Release UQ (freeze /api/sessions cache during streaming)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
+5
-3
@@ -74,6 +74,11 @@ def _session_payload_with_full_messages(session, *, tool_calls=None):
|
|||||||
return raw
|
return raw
|
||||||
|
|
||||||
|
|
||||||
|
def _compact_for_echo_compare(value: str) -> str:
|
||||||
|
"""Normalize visible stream text for duplicate echo detection."""
|
||||||
|
return re.sub(r'\s+', '', str(value or ''))
|
||||||
|
|
||||||
|
|
||||||
# Global lock for os.environ writes. Per-session locks (_agent_lock) prevent
|
# Global lock for os.environ writes. Per-session locks (_agent_lock) prevent
|
||||||
# concurrent runs of the SAME session, but two DIFFERENT sessions can still
|
# concurrent runs of the SAME session, but two DIFFERENT sessions can still
|
||||||
# interleave their os.environ writes. This global lock serializes the env
|
# interleave their os.environ writes. This global lock serializes the env
|
||||||
@@ -6347,9 +6352,6 @@ def _run_agent_streaming(
|
|||||||
stats.setdefault('estimated', False)
|
stats.setdefault('estimated', False)
|
||||||
put('metering', stats)
|
put('metering', stats)
|
||||||
|
|
||||||
def _compact_for_echo_compare(value: str) -> str:
|
|
||||||
return re.sub(r'\s+', ' ', str(value or '')).strip()
|
|
||||||
|
|
||||||
def _is_visible_output_echo(text: str) -> bool:
|
def _is_visible_output_echo(text: str) -> bool:
|
||||||
candidate = _compact_for_echo_compare(text)
|
candidate = _compact_for_echo_compare(text)
|
||||||
if not candidate:
|
if not candidate:
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from api.streaming import _compact_for_echo_compare
|
||||||
|
|
||||||
|
|
||||||
def test_streaming_initializes_one_run_journal_writer_per_stream():
|
def test_streaming_initializes_one_run_journal_writer_per_stream():
|
||||||
src = Path("api/streaming.py").read_text(encoding="utf-8")
|
src = Path("api/streaming.py").read_text(encoding="utf-8")
|
||||||
@@ -21,3 +23,10 @@ def test_streaming_journals_sse_events_before_queue_delivery():
|
|||||||
assert put_idx < journal_idx < queue_idx
|
assert put_idx < journal_idx < queue_idx
|
||||||
assert "Failed to append run journal event" in block
|
assert "Failed to append run journal event" in block
|
||||||
assert "queue_item = (event, data, event_id) if event_id and hasattr(q, \"subscribe_with_snapshot\") else (event, data)" in block
|
assert "queue_item = (event, data, event_id) if event_id and hasattr(q, \"subscribe_with_snapshot\") else (event, data)" in block
|
||||||
|
|
||||||
|
|
||||||
|
def test_visible_process_echo_compare_ignores_all_whitespace():
|
||||||
|
token_text = "先把 issue 4249 拉下来\n\n先看正文和评论"
|
||||||
|
interim_text = "先把 issue 4249 拉下来先看正文和评论"
|
||||||
|
|
||||||
|
assert _compact_for_echo_compare(token_text) == _compact_for_echo_compare(interim_text)
|
||||||
Reference in new issue
Block a user