fix(cron): allow emoji ZWJ sequences in cron prompts#28067
Open
david6ca wants to merge 2 commits into
Open
Conversation
added 2 commits
May 17, 2026 21:11
The persistent typing indicator loop in DiscordAdapter.send_typing()
runs indefinitely until stop_typing() cancels it. If stop_typing() is
ever missed -- e.g. WS reconnect drops the adapter reference, caller
crashes between send_typing() and the finally block, or an asyncio
task sleeps through a chat_id dedup check on a new connection -- the
task continues POST /channels/{id}/typing every 8 seconds forever,
making the bot appear permanently 'typing'. This was observed on a
profile running long opus-4.7 turns (tool_turns=106) across a WS
reconnect; typing persisted for >3 hours after Turn ended.
Add a 30-minute hard cap inside _typing_loop so any leaked task
self-cancels with a WARNING that pinpoints the chat_id, making the
root-cause stop_typing() miss easier to track down on its next
occurrence without permanently spamming the indicator.
_scan_cron_prompt() blocks any U+200D Zero-Width Joiner as 'possible injection'. ZWJ is also a *required* part of many standard Unicode emoji sequences (family, rainbow flag, mending-heart, technologist, ...). Replace the blanket ban with neighbour-aware detection: a ZWJ is allowed when both immediate non-VS neighbours are in pictographic emoji codepoint ranges. Bare ZWJ between ASCII (the actual injection vector) is still blocked.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
tools/cronjob_tools.py::_scan_cron_promptrejects any prompt containingU+200D(Zero-Width Joiner) as 'possible injection'. ZWJ is also a required glue codepoint inside many standard Unicode emoji:Real failure: a daily 时评 cron loads a writing-style skill containing
❤️🩹as a category icon. Every run blocked withBlocked: prompt contains invisible unicode U+200D. Affects any cron whose prompt pulls in skill/wiki text with modern emoji.Fix
Neighbour-aware detection. A ZWJ is accepted iff both immediate non-variation-selector neighbours are in pictographic codepoint ranges (Misc Symbols & Pictographs, Dingbats, Misc Technical, Regional Indicators, Keycap). Variation Selector U+FE0F is skipped on either side so
❤️🩹(U+2764 U+FE0F U+200D U+1FA79) parses correctly.Bare ZWJ between ASCII — the actual injection vector — is still blocked, as are all other invisibles (ZWSP, BOM, RLO/LRO).
Tests
Notes
_CRON_INVISIBLE_CHARSlexical pattern exists intools/memory_tool.py; not touched here, worth a follow-up audit.