fix(gateway): dedupe Telegram voice transcript echoes - #44519
Conversation
7b0d1e8 to
1885f49
Compare
Review: Swapped arguments in testThe dedup approach is solid — removing the echo from the interrupt monitor and relying on However, the tests have the # In test_stt_echo_dedupe_suppresses_immediate_duplicate:
assert runner._mark_stt_echo_sent_once(source, event, ...) is TrueBut the method signature is: def _mark_stt_echo_sent_once(self, source, event, audio_path, transcript) -> bool:Wait — looking again, the test passes The test works by coincidence because This means the test doesn't actually verify that the method reads from the correct parameter. If someone later adds Suggested fix: use keyword arguments in the test to match production callers: assert runner._mark_stt_echo_sent_once(event=event, source=source, audio_path="/tmp/a.ogg", transcript="Проверка") is True |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tracing the monitor/drain duplicate path; current main still has it: the monitor echoes at gateway/run.py:19305-19313, then the retained pending event is drained and echoed again at gateway/run.py:19684, gateway/run.py:19727-19735.
Problems
- The proposed TTL key is
(platform, chat, thread, transcript). It omits event/audio identity, so two distinct voice notes with the same transcript in the same chat within 20 seconds lose a legitimate echo. Current main keeps the pending event from monitor through drain (gateway/run.py:19270-19278), allowing event-scoped state instead. tests/gateway/test_voice_stt_echo_dedupe.pytests only the helper, not the production monitor-to-drain sequence or one-transcription invariant.
Suggested changes
- Cache transcript output and echo-sent state on the pending
MessageEvent, then reuse it in both paths. - Add an async end-to-end regression that asserts one STT call and one
🎙️send for one pending voice event.
Automated hermes-sweeper review.
| # different MessageEvent instances and/or cached file paths by the time | ||
| # the pending-message helper runs. The stable duplicate signal is the | ||
| # same transcript being echoed into the same chat/thread immediately. | ||
| key = (platform, chat_id, thread_id, transcript_key) |
There was a problem hiding this comment.
This key suppresses separate voice messages that happen to produce the same normalized transcript in this chat/thread during the 20-second window. The monitor preserves the queued MessageEvent until post-run drain, so cache/mark the event instead; that identifies the actual duplicate and avoids suppressing a legitimate second note.
|
Closing as fixed on main: Thanks @Adel7418 for the fix; a residual re-echo gap across media merges is being handled separately via #67281. |
Summary
agent.interrupt(...), but stop the interrupt monitor from sending its own user-visible🎙️echo.Why
When a voice message arrives while an agent is already working, it can flow through two paths:
monitor_for_interrupt()peeks at the pending event, transcribes it, and interrupts the agent.That could create two identical
🎙️ "..."Telegram messages for one voice note.Verification
/home/flora/.hermes/hermes-agent/venv/bin/python -m py_compile gateway/run.pygit diff --checkuv pip install --python .venv/bin/python pytestuv run python -m pytest tests/gateway/test_voice_stt_echo_dedupe.py -q -o 'addopts='→2 passed