feat: per-chat routing, group prefix trigger, and conversation history#165
feat: per-chat routing, group prefix trigger, and conversation history#165morellid wants to merge 3 commits intoRichardAtCT:mainfrom
Conversation
Adds three connected features for multi-chat deployments: **Per-chat working directories** New PERSONAL_CHAT_ID / PERSONAL_CHAT_DIRECTORY and GROUP_CHAT_ID / GROUP_CHAT_DIRECTORY settings map specific Telegram chat IDs to dedicated Claude sessions and working directories. Unrecognised chats fall back to APPROVED_DIRECTORY. **Session isolation per chat** All session state now lives in PTB's context.chat_data (keyed by chat ID) instead of context.user_data (keyed by user ID), giving each chat its own independent Claude session even when the same user writes in multiple chats. **Group trigger prefix + conversation history** In group/supergroup chats Claude is silent by default. Only messages starting with GROUP_TRIGGER_PREFIX (default: "claude") — or its slash form (/claude) — produce a response. All other messages are stored in a rolling buffer (last 30 messages). When Claude is triggered, the most recent 20 buffered messages are prepended as context so Claude can follow the conversation without everyone having to address the bot directly.
|
Good concept — per-chat routing and group silencing are genuinely useful features. The implementation is mostly clean but there are a couple of blockers and several things worth addressing before merge. 🔴 Blockers1. No type hints in Violates the project's def append(buffer: list[dict[str, str]], sender_name: str, text: str) -> None: ...
def format_history(messages: list[dict[str, str]]) -> str: ...
def get_working_directory(chat_id: int, settings: Settings) -> str: ...2. No automated tests The group trigger logic has meaningful branching (exact match, prefix match, slash variant, stripping, history injection) and 🟡 Non-blocking issues3. Redundant slice guard # Current
context_messages = history[-HISTORY_CONTEXT_SIZE:] if len(history) > HISTORY_CONTEXT_SIZE else history
# Simplified — slice handles the short-list case natively
context_messages = history[-HISTORY_CONTEXT_SIZE:]4.
5. Telegram slash commands with In groups, Telegram often appends the bot username: slash_variants = (slash_prefix + " ", slash_prefix + "@")6. Buffer is stored in 7. Prefer telegram constants from telegram import Chat
if chat_type in (Chat.GROUP, Chat.SUPERGROUP):8. A class with only ✅ What's good
Summary: Fix the type hints and add at least basic unit tests for the pure functions in — Friday, AI assistant to @RichardAtCT (posted as @RichardAtCT — FridayOpenClawBot access pending) |
Summary
PERSONAL_CHAT_ID/PERSONAL_CHAT_DIRECTORYandGROUP_CHAT_ID/GROUP_CHAT_DIRECTORYsettings map specific Telegram chat IDs to dedicated Claude sessions and working directories. Unrecognised chats fall back toAPPROVED_DIRECTORY.claude_session_id,force_new_session, etc.) moved fromcontext.user_data(per-user) tocontext.chat_data(per-chat), so each chat gets an independent Claude session even for the same user.GROUP_TRIGGER_PREFIX(default:claude) — or the slash form/claude— produce a response. All other messages are stored in a rolling buffer (last 30 messages); when Claude is triggered the most recent 20 are prepended as context.New files
src/bot/features/chat_routing.py—get_working_directory()routing helper andGroupChatBufferrolling history bufferChanged files
src/config/settings.py— 5 new optional fields + validatorssrc/bot/orchestrator.py— useschat_datafor session state; group prefix filter inagentic_text,agentic_document, and_handle_agentic_media_message.env.example— documents the new settingsTest plan
PERSONAL_CHAT_DIRECTORY, session is independent from groupclaude <request>or/claude <request>in the group → Claude responds with recent conversation as context/newin DM resets only the DM session, group session unaffectedAPPROVED_DIRECTORY, no group filtering)