Conversation
- Convert markdown tables to aligned monospace <pre> blocks - Add blockquote support (> text → <blockquote>) - Add bullet list conversion (- item → • item) - Add numbered list formatting - Add horizontal rule conversion (--- → ──────────) - Fix HTML tag nesting issues that cause Telegram rejection - Add _repair_html_nesting() to fix overlapping bold/italic tags
In agentic mode, unknown slash commands (e.g. /workflow, /skill, /add-memory) were silently dropped because the TEXT handler excluded all COMMAND messages. Remove ~filters.COMMAND from the agentic text handler so unrecognised slash commands are forwarded to Claude as natural language. Registered commands (/start, /new, /status, etc.) still take priority via higher-priority CommandHandlers and are unaffected. Classic (non-agentic) mode retains the original filter — unknown commands are not forwarded there. Closes RichardAtCT#129
Previous approach (removing ~filters.COMMAND) caused registered commands like /start and /new to fire twice — once via CommandHandler (group 0) and again via the agentic text handler (group 10). Fix: revert TEXT filter and add a separate filters.COMMAND MessageHandler in group 10 that dispatches to _handle_unknown_command(). That method checks the command name against KNOWN_COMMANDS and returns early for registered ones, forwarding only truly unknown slash commands to Claude. Dispatch flow: - /start, /new, /status ... -> CommandHandler (group 0) only - /workflow, /skill, /add-memory ... -> forwarded to Claude via agentic_text - Regular text -> TEXT & ~filters.COMMAND handler as before Also updates test to expect 5 message handlers (was 4).
…ation, routing tests - Add ClassVar[frozenset[str]] type annotation on _known_commands (mypy strict) - Derive _known_commands dynamically from registered handlers list to prevent drift when new commands are added in future - Remove hardcoded KNOWN_COMMANDS class variable - Add 3 routing tests: - test_known_command_not_forwarded_to_claude - test_unknown_command_forwarded_to_claude - test_bot_suffixed_command_not_forwarded
Allow users to switch Claude models at runtime without restarting the bot. Supports aliases (sonnet, opus, haiku), full model names, and /model default to reset. Override is per-user.
- Add audit logging to /model set and reset paths - Update last_model in _handle_agentic_media_message - Add input validation (max length) for model name - Add tests for audit logging and long model name rejection
Log model set as command="model" and reset as command="model_reset" with empty args for cleaner audit log queries.
- Rewrite DraftStreamer with group chat fallback (editMessageText) - Add cursor ▌ during streaming for visual feedback - Min initial chars gate (20 chars before first send) - Anti-regressive updates (skip if text got shorter) - Smart error classification (draft unavailable → edit fallback) - Support verbose level 3 (full tool output)
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.
Summary
Cherry-picks 4 high-value open PRs from upstream (RichardAtCT/claude-code-telegram):
.claude/commands/skills via Telegram)/modelcommand for per-user runtime model switching with audit loggingsendMessageDraftwith fallback toeditMessageTextDetails
Rich HTML Formatting (RichardAtCT#145)
14-step markdown→Telegram HTML conversion pipeline: aligned monospace tables with box-drawing characters,
<blockquote>support, bullet/numbered lists, horizontal rules, and a stack-based_repair_html_nesting()fixer for strict Telegram tag validation.Slash Command Passthrough (RichardAtCT#131)
Forwards unrecognized
/commandsto Claude as natural language via a fallbackCommandHandler. Dynamically builds a_known_commandsset from registered handlers to avoid double-firing. Handles@botsuffixed commands correctly.Model Switching (RichardAtCT#139)
/modelshows current model (source: user override, server config, or Claude Code default)./model <name>sets a per-user override./model defaultresets. Threaded through orchestrator→facade→SDK. Includes input validation, audit logging, and 14 tests.Streaming Drafts (RichardAtCT#146)
Rewrites
DraftStreamerto usesendMessageDraftin private chats witheditMessageTextfallback for groups. Anti-regressive updates, smart error classification, self-disabling after 3 errors. New config:ENABLE_STREAM_DRAFTS,STREAM_DRAFT_INTERVAL.Test plan
/workflow,/skill) are forwarded to Claude/start,/help) still work normally/model,/model sonnet,/model defaultlifecycle🤖 Generated with Claude Code