fix(gateway): sanitize lone surrogates before platform delivery - #55326
fix(gateway): sanitize lone surrogates before platform delivery#55326AlexFucuson9 wants to merge 1 commit into
Conversation
Fixes NousResearch#55309 _sanitize_gateway_final_response() redacted secrets and classified provider errors but did not strip lone surrogate code points (U+D800-U+DFFF). These are invalid in UTF-8 and crash the utf-16-le length check in Telegram delivery, aborting the send for the entire reply. The codebase already had _sanitize_surrogates() in agent/message_sanitization.py (used for history storage), but it was never applied to the delivered copy. Add it as the final step in _sanitize_gateway_final_response() so all chat surfaces receive surrogate-safe text.
Duplicate of #55310 (earliest open canonical fix for #55309, paired with the issue by its author). Same |
tonydwb
left a comment
There was a problem hiding this comment.
LGTM. Strips lone surrogate code points that crash utf-16 encoding in platform length checks. Clean fix.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tracing the non-streaming final-response boundary; current main still returns ordinary chat replies unsanitized at gateway/run.py:434-437, so that portion addresses a real defect.
Problems
- Streaming bypasses this helper:
gateway/run.py:18123-18125forwards raw deltas toGatewayStreamConsumer.on_delta, which queues them unchanged atgateway/stream_consumer.py:370-379and later edits through the adapter atgateway/stream_consumer.py:1771-1775. Telegram measures edit content with strict UTF-16 encoding atplugins/platforms/telegram/adapter.py:3980, so a lone surrogate can still abort delivery before this final-response path runs. - The diff changes only
gateway/run.py; it adds no regression test.tests/gateway/test_telegram_noise_filter.py:79-243has final-response coverage but no lone-surrogate case.
Suggested changes
- Retain the final-response sanitization and sanitize deltas at the stream-consumer input boundary; add non-streaming and streaming Telegram regressions that prove the downstream UTF-16 measurement accepts the delivered content.
- Keep raw programmatic surfaces unchanged, consistent with
gateway/run.py:421-427.
Automated hermes-sweeper review.
| # utf-16-le encoding in platform length checks (e.g. Telegram). | ||
| from agent.message_sanitization import _sanitize_surrogates | ||
| return _sanitize_surrogates(redacted) | ||
|
|
There was a problem hiding this comment.
Please add a regression test for this final-response boundary, and cover the streaming path separately: raw deltas bypass this helper via gateway/run.py:18123-18125 → GatewayStreamConsumer.on_delta, then reach adapter edits before the final sanitizer can run.
Fixes #55309
_sanitize_gateway_final_response()redacted secrets and classified provider errors but did not strip lone surrogate code points (U+D800-U+DFFF). These are invalid in UTF-8 and crash theutf-16-lelength check in Telegram delivery, aborting the send for the entire reply.The codebase already had
_sanitize_surrogates()inagent/message_sanitization.py(used for history storage), but it was never applied to the delivered copy.Fix: Apply
_sanitize_surrogates()as the final step in_sanitize_gateway_final_response()so all chat surfaces receive surrogate-safe text.Reproduction (before fix):
After fix: lone surrogates are replaced with U+FFFD before reaching platform adapters.