Skip to content

Repository files navigation

Zerde Bot

English | Қазақша | Русский

Python uv pre-commit Code style: black Linted_by: Flake8 AWS CDK AWS Lambda DynamoDB S3 Vectors Google Gemini License

Zerde is a serverless Telegram bot for IT communities. It started as a simple LLM wrapper and community-management bot; it is now an agentic group-chat bot with RAG memory. It can answer explicit /ask prompts, follow reply threads, remember group context, retrieve relevant long-term memories, and decide when it is socially useful to join a conversation.

The bot still handles moderation, captcha, voteban, daily AI news digests, and tech quizzes. The current architecture is optimized for small community workloads on AWS serverless infrastructure.


What Changed

Zerde is no longer "just call an LLM with the latest message." The bot now has:

  • Recent memory: non-command group messages stored in DynamoDB as MSG#....
  • User profiles: lightweight per-user context derived from each user's own messages.
  • Long-term memory: candidate-gated, budgeted schema extraction for EVENT#..., USER_FACT#..., GROUP_FACT#..., conservative JOKE#..., and DAILY_SUMMARY#... items, with rule fallback.
  • Hybrid RAG: long-term memories embedded with Gemini for S3 Vectors semantic retrieval, plus DynamoDB lexical fallback and local reranking.
  • Agent behavior: explicit /ask, @mention handling, self-reference grounding, reply-to-bot thread continuity, immediate linked-channel post comments, delayed AI-decided ordinary proactive replies, reply-length/style budgeting, and /agent why source summaries.
  • Ambient reactions: optional emoji reactions to group messages, classified through a Groq model pool and processed asynchronously without writing long-term memory. Linked-channel posts force a reaction attempt and fall back to 👀.
  • Explicit media understanding: /ask can be used as a reply to photos/screenshots, voice/audio, PDFs, and supported text/code/log files. Linked-channel post comments may also analyze supported attached media ephemerally. Zerde does not automatically analyze ordinary group media messages.
  • Memory controls: /memory, /agent, /memory about me, /memory forget me, /memory forget this durable source cleanup, and /agent wrong / /memory wrong feedback with related vector cleanup and owner-only group cleanup commands.
  • Bot output boundary: normal bot answers are stored only as short-term AGENT_REPLY#... thread metadata, not embedded into semantic memory. Durable bot-authored memory is reserved for explicit future BOT_COMMITMENT#... or BOT_CORRECTION#... flows.

ZerdeBot does not automatically analyze every group media message. It analyzes media only when explicitly asked via /ask or an explicit mention/reply path, plus official linked-channel post comments. Media analysis is ephemeral and is not written into long-term memory or vector storage by default. The bot does not store raw bytes or downloaded files; only compact media metadata/summary may be stored in short-lived AGENT_REPLY#... rows for follow-up continuity.

RAG means Retrieval-Augmented Generation: retrieve relevant memory first, then ask the LLM to answer with that context. Zerde uses RAG as one layer inside a larger group-chat agent.


Key Features

Feature Description
Group-chat agent Answers /ask, @mentions, and replies to bot messages with requester, recent, profile, long-term, lexical, and semantic memory context.
Explicit multimodal /ask Reply to photos/screenshots, voice/audio, PDFs, or supported text/code/log files with /ask; the async worker reads that media for the current answer only.
RAG memory Stores group memory in DynamoDB, extracts long-term memory with a structured Gemini schema plus rule fallback, indexes high-information memory in S3 Vectors for semantic retrieval, and uses exact-term DynamoDB fallback plus local reranking.
Reply thread continuity Records bot answers in short-term AGENT_REPLY#... items so follow-up replies know what the bot just said; these rows are not semantic/vector memory.
Social timing Ordinary proactive replies are delayed briefly, then a Groq model pool decides from capped recent and query-filtered long-term context whether the bot can add value. If yes, the chat daily limit is reserved and Gemini generates with DeepSeek/Groq fallback. Linked channel posts mirrored into discussion groups use a separate zero-delay comment path and may analyze supported attached media.
Ambient reactions Optional setMessageReaction presence feature for funny, useful, thoughtful, warm, or interesting messages; enabled by default. Ordinary messages are sampled/rate-limited, while linked-channel posts force a reaction attempt.
Smart captcha and anti-spam Mutes new members until verification; pending captcha messages stay in captcha handling, strong high-confidence spam is removed silently, and weak or ambiguous cases go to admin review with optional admin @mentions.
Community voteban Lets communities vote to ban or forgive by replying with /voteban.
Daily AI news EventBridge-triggered news Lambda enriches RSS candidates with article text/images, ranks high-signal developer stories, and sends fact-first multilingual digests through Gemini/DeepSeek-compatible provider paths.
IT quizzes Scheduled and on-demand quiz Lambda sends multilingual developer quizzes and tracks scores.
Serverless operations AWS CDK manages Lambda, API Gateway, DynamoDB, SQS, EventBridge, S3 Vectors, IAM, and alarms.

Architecture

flowchart LR
  TG["Telegram groups"] --> APIGW["HTTP API Gateway"]
  APIGW --> BOT["Bot Lambda<br/>webhook + main SQS worker"]

  BOT --> STATS[("DynamoDB<br/>stats / captcha / votes")]
  BOT --> MEMORY[("DynamoDB<br/>group memory")]
  BOT --> MAINQ["SQS timeout/tasks queue"]
  MAINQ --> BOT

  BOT -- "enqueue vector tasks" --> VQ["SQS vector memory queue"]
  VQ --> VIDX["Vector indexer Lambda"]
  BOT -- "query/delete" --> S3V["S3 Vectors<br/>semantic memory index"]
  VIDX -- "index/backfill" --> S3V
  VIDX --> MEMORY

  BOT --> GEMINI["Gemini<br/>agent replies / summaries"]
  VIDX --> GEMINI_EMB["Gemini<br/>embeddings"]
  BOT --> GROQ["Groq<br/>spam checks"]
  BOT --> DEEPSEEK["DeepSeek<br/>ambient fallback"]

  EB["EventBridge schedules"] --> NEWS["News Lambda"]
  EB --> QUIZ["Quiz Lambda"]
  NEWS --> GEMINI
  QUIZ --> GEMINI
  NEWS --> TG
  QUIZ --> TG

  LAYER["Shared Lambda layer<br/>zerde_common"] -.-> BOT
  LAYER -.-> VIDX
  LAYER -.-> NEWS
  LAYER -.-> QUIZ
Loading
Component Trigger Responsibility
src/bot/main.py API Gateway + main SQS queue Telegram webhook, captcha, voteban, spam screening, /ask, agent replies, group memory extraction, daily summaries, semantic retrieval, and vector cleanup/enqueue.
src/bot/vector_indexer_main.py Vector memory SQS queue Dedicated consumer for PROCESS_VECTOR_MEMORY and PROCESS_VECTOR_MEMORY_BACKFILL; embeds/indexes memory in S3 Vectors and fans out backfill pages.
src/news/ EventBridge Scheduled multilingual IT news digest.
src/quiz/ EventBridge + bot invoke Scheduled and on-demand developer quizzes.
src/shared/python/zerde_common/ Lambda layer Shared config, secret loading, logging, redaction, and provider error helpers.
infra/ CDK Serverless infrastructure, queues, tables, vector bucket/index, alarms, and Lambda wiring.

The Bot Lambda can query and delete S3 Vectors for retrieval and memory cleanup, but it does not consume the vector memory queue.

For the deeper developer map, see docs/ARCHITECTURE.md.


Bot Commands

Command Who Description
/start Everyone Restart the bot and view instructions.
/help Everyone Show usage guide and available commands.
/ping Everyone Health check.
/support Everyone Developer contact info.
/stats Admins Community statistics.
/voteban Everyone Reply to a message to start a ban vote.
/quizstats Everyone Personal quiz score, streak, and rank.
/ask <question> Everyone in memory-enabled groups Ask the agent; can be used as a reply to another message, image/screenshot, voice/audio, PDF, or supported text/code/log file. Media is analyzed only for that explicit answer and is not stored as long-term/vector memory by default.
/memory about me Everyone Show the current user's own stored profile fields without showing other users' claims.
/memory on/off/status/forget .../wrong Group owner or bot owner for settings; users can delete their own memory or mark answer sources wrong Manage group memory and cleanup. forget this deletes durable long-term memory from a replied bot answer, or raw/derived memory when replying directly to a source message; it does not delete USER# profiles. wrong marks a replied bot answer's memory sources as wrong without deleting them.
/agent on/off/status/why/wrong Group owner or bot owner for settings; everyone can inspect or mark replied answer sources Manage agent participation and inspect why the bot replied, including memory source types and counts without full memory text. /agent wrong marks a replied bot answer's memory sources as wrong. /agent off disables proactive, mention, and reply-thread participation; /ask remains available if memory is on.

Chat Style Settings

Each chat SETTINGS item can include a style_profile map for agent replies:

  • tone: concise, professional, or friendly
  • max_default_sentences: default answer sentence cap, default 5
  • max_proactive_sentences: proactive reply sentence cap, default 2
  • allow_light_humor: default false
  • low_confidence_behavior: cautious, avoid_weak_memory, or none

Defaults keep replies concise. When selected memory is low confidence or weakly matched, the default cautious behavior tells the model to avoid sounding certain and use wording such as "I may be remembering this imperfectly."


Development

uv sync --frozen
uv run pytest tests/ -q
uv run pre-commit run --all-files

Infrastructure validation:

cd infra
uv run cdk synth -c env=dev
uv run cdk diff -c env=dev

Common group-memory retention settings:

Env var Applies to Default
GROUP_MEMORY_RAW_MESSAGE_RETENTION_DAYS Raw recent MSG#... records 30
GROUP_MEMORY_AGENT_REPLY_RETENTION_DAYS AGENT_REPLY#... reply-thread metadata 7
GROUP_MEMORY_LONG_TERM_RETENTION_DAYS EVENT#..., USER_FACT#..., GROUP_FACT#..., JOKE#... 3650
GROUP_MEMORY_DAILY_SUMMARY_RETENTION_DAYS DAILY_SUMMARY#... records 3650
GROUP_MEMORY_PROACTIVE_COUNTER_RETENTION_DAYS PROACTIVE#YYYYMMDD counters 3
GROUP_MEMORY_RETENTION_DAYS Legacy fallback for broad memory retention settings when omitted 3650

MSG#..., long-term memory, and DAILY_SUMMARY#... retention settings fall back to GROUP_MEMORY_RETENTION_DAYS when omitted. AGENT_REPLY#... and PROACTIVE#... keep their existing short defaults unless explicitly configured. Long-term memory still stores explicit expires_at metadata from expires_in_days; DynamoDB TTL uses the shorter of that explicit expiry and the configured long-term retention.

Proactive decision settings:

Env var Applies to Default
AGENT_PROACTIVE_DECISION_GROQ_MODELS Comma-separated Groq model pool for ordinary proactive decisions llama-3.1-8b-instant,meta-llama/llama-4-scout-17b-16e-instruct,qwen/qwen3-32b
AGENT_PROACTIVE_DECISION_CONTEXT_CHARS Max recent/query-filtered context characters sent to decision models 4000
AGENT_PROACTIVE_DECISION_ALLOW_DEEPSEEK_FALLBACK Opt-in DeepSeek fallback for proactive decisions when every Groq model fails false

Ambient reaction settings:

Env var Applies to Default
AMBIENT_REACTIONS_ENABLED Enables async ambient emoji reactions true
AMBIENT_REACTIONS_SAMPLE_RATE Fraction of eligible messages sampled before SQS enqueue 0.80
AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD Minimum classifier confidence before reacting 0.80
AMBIENT_REACTIONS_DECISION_GROQ_MODELS Comma-separated Groq model pool for reaction decisions llama-3.1-8b-instant,qwen/qwen3-32b,meta-llama/llama-4-scout-17b-16e-instruct
AMBIENT_REACTIONS_DECISION_CONTEXT_CHARS Max previous/reply context characters sent to reaction decision models 3000
AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS Minimum seconds between reactions in one chat 60
AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS Minimum seconds between reactions to one user's messages in a chat 300
AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR Per-chat hourly reaction cap 12
AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY Per-chat daily reaction cap 100

Explicit multimodal /ask settings:

Env var Applies to Default
MULTIMODAL_ENABLED Enables explicit /ask media analysis true
MULTIMODAL_MAX_DOWNLOAD_BYTES Telegram download cap for one explicit media request 12000000
MULTIMODAL_INLINE_MAX_BYTES Gemini inline media cap; larger binary media is rejected in this first version 8000000
MULTIMODAL_TEXT_FILE_MAX_CHARS Text/code/log file content included in the prompt 20000

See CONTRIBUTING.md for setup and docs/LOCAL_TESTING.md for a full AWS + Telegram walkthrough.


History

Zerde was originally built from the serverless-tg-bot-starter template. That starter remains useful for simple serverless Telegram bots. This repository has since grown into a memory-enabled agentic bot with separate news and quiz workloads.


License

This project is licensed under the MIT License.

About

🛡️ Serverless Telegram Bot for IT Community Management. Features Anti-spam verification (Captcha), User analytics, and Group protection. Built with Python, AWS CDK, and DynamoDB.

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages