Voice utterances and text messages on the same Discord channel now share one Claude session, and Echo's voice replies are mirrored back into the text channel. Replaces the old voice:<id> session-key split. Changes: - src/adapters/_text_chunks.py: new leaf module for split_message (used by both discord_bot and voice pipeline) - src/router.py: drop voice: prefix from session_key; add [voice] marker; strip leading [speaker:/[voice] tokens from user input (anti-jailbreak); remove dead double-clear of voice: key - src/claude_session.py: include personality/VOICE_MODE.md unconditionally (rules become per-turn-aware via [speaker:] prefix instead of session flag) - src/voice/pipeline.py: VoiceSession splits text_channel_id + voice_channel_id; resolve text channel per-send (no stale refs); mirror Echo's reply text into the text channel after route_message returns - src/adapters/discord_voice.py: /voice join passes both channel ids - src/adapters/discord_bot.py: import split_message from leaf module - personality/VOICE_MODE.md: rewrite as per-turn dynamic rules; add synthesis instructions for text turns after voice turns Tests: - tests/test_router.py: 4 new cases (plain channel_id, anti-jailbreak, text-adapter regression, no-double-clear) - tests/test_pipeline_mirror.py: new — Echo reply mirror chunking, empty guard, mirror_enabled=False, send-raises resilience - tests/test_voice_session_channel_ids.py: new — split-attr contract + metrics payload schema - tests/test_voice_session_cleanup.py: update for new kwargs Plan: /home/moltbot/.claude/plans/vreau-ca-tot-textul-greedy-rivest.md Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
20 lines
585 B
Python
20 lines
585 B
Python
"""Leaf module — message chunking helper for Discord (2000 char limit). Zero deps."""
|
|
|
|
|
|
def split_message(text: str, limit: int = 2000) -> list[str]:
|
|
"""Split text into chunks that fit Discord's message limit."""
|
|
if len(text) <= limit:
|
|
return [text]
|
|
|
|
chunks = []
|
|
while text:
|
|
if len(text) <= limit:
|
|
chunks.append(text)
|
|
break
|
|
split_at = text.rfind('\n', 0, limit)
|
|
if split_at == -1:
|
|
split_at = limit
|
|
chunks.append(text[:split_at])
|
|
text = text[split_at:].lstrip('\n')
|
|
return chunks
|