Skip to content

fix(cron): allow emoji ZWJ sequences in cron prompts#28067

Open
david6ca wants to merge 2 commits into
NousResearch:mainfrom
david6ca:fix/cron-emoji-zwj-allowlist
Open

fix(cron): allow emoji ZWJ sequences in cron prompts#28067
david6ca wants to merge 2 commits into
NousResearch:mainfrom
david6ca:fix/cron-emoji-zwj-allowlist

Conversation

@david6ca

Copy link
Copy Markdown

Problem

tools/cronjob_tools.py::_scan_cron_prompt rejects any prompt containing U+200D (Zero-Width Joiner) as 'possible injection'. ZWJ is also a required glue codepoint inside many standard Unicode emoji:

Emoji Sequence
👨‍👩‍👧 family
🏳️‍🌈 rainbow flag
❤️‍🩹 mending heart
🧑‍💻 technologist

Real failure: a daily 时评 cron loads a writing-style skill containing ❤️‍🩹 as a category icon. Every run blocked with Blocked: 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

emoji ZWJ (4 sequences) → PASS
bare ZWJ between ASCII  → BLOCK
mixed (emoji + bare)    → BLOCK
other invisibles (ZWSP) → BLOCK (untouched)

Notes

  • Same _CRON_INVISIBLE_CHARS lexical pattern exists in tools/memory_tool.py; not touched here, worth a follow-up audit.
  • No behaviour change for prompts without ZWJ (early-out).

david6 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.
@alt-glitch alt-glitch added type/bug Something isn't working comp/cron Cron scheduler and job management platform/discord Discord bot adapter P2 Medium — degraded but workaround exists labels May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cron Cron scheduler and job management P2 Medium — degraded but workaround exists platform/discord Discord bot adapter type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants