Quoted Reply Context

Agents see what a user replied to or quoted, so \"do the second one\" resolves to the right referent

When a user replies to or quotes an earlier message on Telegram, the referenced text is folded into the agent turn as a compact quoted block so the agent honours the referent.

Diagram

Quoted Reply Context

πŸ’¬ User taps Reply
on earlier message

πŸ”Ž Adapter resolves
reply_to_message / quote span

πŸ“ Prompt: [In reply to: …]
+ new text

🧠 Agent honours
the referent

Tapping Reply on the bot’s own message now carries the referenced text β€” so a bare “do the second one” resolves correctly:

text
Bot:  Here are three options: 1) migrate now  2) stage it  3) roll back
User: (taps Reply on the bot's message) do the second one

# What the agent sees (rendered by BotMessage.prompt_text)
[In reply to: "Here are three options: 1) migrate now  2) stage it  3) roll back"]
do the second one

# Agent replies with the right referent β€” "Staging it β€” here's the plan…"

Quick Start

  1. Start the bot β€” context is always on
    python
    from praisonaiagents import Agent
    from praisonai.bots import TelegramBot
    
    agent = Agent(name="Planner", instructions="Be concise.")
    bot = TelegramBot(token="...", agent=agent)
    
    import asyncio
    asyncio.run(bot.start())
    # Reply/quote context is always on β€” no flag to enable.
  2. Inspect the resolved quote programmatically
    python
    from praisonaiagents.bots import BotMessage, QuotedRef
    
    msg = BotMessage(
        content="do the second one",
        quoted=QuotedRef(
            text="Here are three options: 1) migrate now  2) stage it  3) roll back",
            author="bot",
        ),
    )
    print(msg.prompt_text)
    # [In reply to: "Here are three options: 1) migrate now  2) stage it  3) roll back"]
    # do the second one

How It Works

The adapter resolves the referenced text inbound, then prompt_text renders it above the new text before the message reaches the agent.

Diagram
AgentMESSAGE_RECEIVEDTelegram adapterTelegramUserAgentMESSAGE_RECEIVEDTelegram adapterTelegramUsermessage.quoted cleared β†’ no re-append post-hook(silent β€” never dispatched)alt[Hook allows unchanged][Hook rewrites content (redaction)][Hook denies](Reply on bot msg) “do the second one”update with reply_to_message + quote?_resolve_quoted_ref β†’ QuotedRef(text=…, author=”bot”)content = prompt_text (folds quoted block above text)allow“[In reply to: …]\ndo the second one”modified_input.content = “[REDACTED]”“[REDACTED]”deny

prompt_text whitespace-collapses the referenced text and truncates anything over 500 characters with an ellipsis. With no quote it is identical to the plain text.

SituationWhat the agent sees
No reply / no quoteOriginal text unchanged
Reply to a bot message[In reply to: "<bot's earlier text>"]\n<new text>
Reply to a peer message[In reply to: "<peer's earlier text>"]\n<new text>
Explicit quote span (partial highlight)[In reply to: "<selected span only>"]\n<new text>
Referenced message has caption onlyCaption used as the quoted text
New text empty (reply with just a sticker/reaction)Only the [In reply to: "…"] block
Quoted text > 500 charsTruncated with …

Behavioural rules:

  • Always-on. No YAML or Python flag β€” the feature is default behaviour on Telegram.
  • Best-effort. Any missing field or error falls back to today’s behaviour β€” the turn is never dropped just because resolution failed.
  • Context, never control. Quoted content is injected as context only, never as a control frame β€” consistent with allow_control on BotMessage.
  • Runs behind the gate. MESSAGE_RECEIVED sees content = prompt_text (the rendered turn including the quoted block). Redacting content in the hook is authoritative β€” the separately-resolved quote is cleared so unredacted quoted text can’t leak past.
  • Works in the standalone bot and the gateway. Both praisonai bot and praisonai gateway render prompt_text before dispatch.

Platform Support

Quoted reply resolution is wired on Telegram in this release. On Discord and Slack a reply to the bot still counts as addressing it (see Implicit Mentions), but the replied-to message’s text is not folded into the agent turn.

PlatformQuoted reply resolved?
Telegramβœ…
Discord❌ (not yet)
Slack❌ (not yet)
WhatsApp❌ (not yet)

Common Patterns

Do nothing β€” it just works. Start the bot and reply/quote context is folded in automatically.

python
from praisonaiagents import Agent
from praisonai.bots import TelegramBot

agent = Agent(name="Planner", instructions="Be concise.")
bot = TelegramBot(token="...", agent=agent)

import asyncio
asyncio.run(bot.start())

Redact quoted secrets before the agent sees them. The MESSAGE_RECEIVED hook receives the rendered turn, so scrubbing event_data.content covers a secret that appeared in the quoted message, not just the new text.

python
import re
from praisonaiagents.hooks import HookRegistry, HookEvent, HookResult

SECRET = re.compile(r"hunter\d+")
registry = HookRegistry()

@registry.on(HookEvent.MESSAGE_RECEIVED)
def redact(event_data):
    cleaned = SECRET.sub("[REDACTED]", event_data.content)
    if cleaned != event_data.content:
        return HookResult(decision="allow", modified_input={"content": cleaned})
    return HookResult.allow()

Inspect msg.quoted in a custom hook or plugin. The resolved reference exposes the referenced text and its author.

python
from praisonaiagents.bots import BotMessage, QuotedRef

msg = BotMessage(
    content="do the second one",
    quoted=QuotedRef(
        text="Here are three options: 1) migrate now  2) stage it  3) roll back",
        author="bot",
    ),
)
print(msg.quoted.author)   # "bot"
print(msg.prompt_text)     # rendered turn with the quoted block

Best Practices

Don't add prompt guidance for quotes

The [In reply to: "…"] block is unambiguous β€” the agent honours the referent without extra system-prompt scaffolding.

Use the inbound gate to filter quoted content

MESSAGE_RECEIVED sees the rendered turn β€” redact or deny there, not by peeking at msg.quoted in the agent tools.

Treat quoted content as untrusted

It comes from whoever sent the referenced message. It is context, never a control frame.

Expect graceful degradation across Telegram clients

If a client doesn’t send the quote span, the adapter falls back to reply_to_message.text / caption; if neither is present, the turn goes through unchanged.


Related