fix(wecombot): preserve throttled snapshots for empty final frames

This commit is contained in:
WangCham
2026-10-28 20:46:15 +08:00
parent 76873c85e7
commit bab86430e6
2 changed files with 61 additions and 1 deletions
+15 -1
View File
@@ -140,6 +140,8 @@ class WecomBotWsClient:
self._stream_ids: dict[str, str] = {} # msg_id -> req_id|stream_id
# Dedup: skip sending when content hasn't changed
self._stream_last_content: dict[str, str] = {} # msg_id -> last content sent
# Latest accepted snapshot, including frames skipped by the throttle.
self._stream_latest_content: dict[str, str] = {}
# Throttle: msg_id -> monotonic timestamp of the last frame sent
self._stream_last_push_at: dict[str, float] = {}
# Preserve completion identity after removing active stream mappings.
@@ -180,6 +182,7 @@ class WecomBotWsClient:
self._stream_sessions.pop(msg_id, None)
self._stream_ids.pop(msg_id, None)
self._stream_last_content.pop(msg_id, None)
self._stream_latest_content.pop(msg_id, None)
self._stream_last_push_at.pop(msg_id, None)
task_id = self._task_id_by_msg.pop(msg_id, None)
if task_id:
@@ -261,6 +264,7 @@ class WecomBotWsClient:
self._callback_tasks.clear()
self._stream_ids.clear()
self._stream_last_content.clear()
self._stream_latest_content.clear()
self._stream_last_push_at.clear()
self._stream_sessions.clear()
self._feedback_sessions.clear()
@@ -446,6 +450,7 @@ class WecomBotWsClient:
self._stream_ids.pop(msg_id, None)
self._stream_last_content.pop(msg_id, None)
self._stream_latest_content.pop(msg_id, None)
self._stream_last_push_at.pop(msg_id, None)
self._stream_sessions.pop(msg_id, None)
return True, stream_id, None
@@ -482,6 +487,7 @@ class WecomBotWsClient:
# push_stream_chunk calls for this msg_id become no-ops.
self._stream_ids.pop(msg_id, None)
self._stream_last_content.pop(msg_id, None)
self._stream_latest_content.pop(msg_id, None)
self._stream_last_push_at.pop(msg_id, None)
# Keep _stream_sessions so the button callback can still resolve
# user/chat context; it gets cleaned up when the click fires.
@@ -691,10 +697,17 @@ class WecomBotWsClient:
previous_content = self._stream_last_content.get(msg_id, '')
# Pipeline delivery provides complete snapshots, including edits
# that need not start with the previous text (e.g. reasoning tags).
next_content = content or previous_content
next_content = content or self._stream_latest_content.get(msg_id, previous_content)
if len(next_content) > _MAX_STREAM_CONTENT_CHARS:
next_content = next_content[-_MAX_STREAM_CONTENT_CHARS:]
# Remember valid snapshots before deduplication: an edit can revert
# a throttled snapshot to the last sent text before an empty final.
import re as _re
if _re.sub(r'[\s\u200b\u200c\u200d\ufeff]', '', next_content):
self._stream_latest_content[msg_id] = next_content
# Skip sending if content hasn't changed (e.g. during tool call argument streaming)
if not is_final and next_content == previous_content:
return True
@@ -760,6 +773,7 @@ class WecomBotWsClient:
self._cap_mapping(self._completed_stream_content, _STREAM_CACHE_MAX)
self._stream_ids.pop(msg_id, None)
self._stream_last_content.pop(msg_id, None)
self._stream_latest_content.pop(msg_id, None)
self._stream_last_push_at.pop(msg_id, None)
self._stream_sessions.pop(msg_id, None)
return True