You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adds a new agent-facing built-in tool: send_message. Lets a running agent proactively reach the user mid-task on the channel the conversation came from (or any other configured channel) through the existing gateway delivery stack — and list reachable targets.
Before this change, proactive delivery was only reachable from the scheduler or the gateway send CLI; an agent had no way to message the user during a task.
Doc action required
Type: NEW PAGE (no existing docs page covers this; existing send_message references in the docs are about bot adapter methods, not the new agent-facing tool).
File to create:docs/features/send-message-tool.mdx
Folder:docs/features/ (per AGENTS.md §1.8 — never docs/concepts/).
Pattern to mirror:docs/features/clarify-tool.mdx — same shape (agent-facing built-in that resolves a per-turn handler/messenger from context; fails cleanly when not available).
Add to docs.json: under the Features group, NEVER under Concepts. Do not modify auto-generated docs/js/ or docs/rust/ entries.
SDK ground truth (read before writing)
The implementation agent MUST read these files in MervinPraison/PraisonAI before writing the page (per AGENTS.md §1.2 SDK-first cycle):
Symbolic destination. One of: "origin" (chat the conversation came from), "<platform>" (platform's home channel, e.g. "telegram"), "<platform>:<chat_id>[:<thread_id>]" (explicit chat), or a friendly alias for a known target.
message
str
""
Text to send. Append " MEDIA:<path>" one or more times to attach local files, e.g. "Report ready MEDIA:/tmp/report.pdf".
action
str
"send"
"send" to deliver a message, or "list" to return a JSON array of reachable targets.
Returns
action="send": human-readable summary string (e.g. "Delivered to slack:#ops", or "Failed to send to ...: <detail>").
action="list": JSON string of [{target, platform, kind, label}, ...] — kind is one of "origin", "home", "alias".
When it's available
Available when running inside a gateway/bot (Telegram, Slack, Discord, WhatsApp, etc.) — the gateway registers an OutboundMessengerProtocol impl into the per-turn context.
Unavailable for plain CLI / one-shot runs. The tool does not raise — it returns the literal string:
"No active gateway: send_message is only available inside a running bot/gateway (e.g. Telegram, Slack, Discord). It is unavailable for CLI/one-shot runs."
This graceful-fallback behaviour must be documented (mirror how clarify-tool.mdx documents its fallback).
Required page structure (per AGENTS.md §2)
Use this exact skeleton. Fill from SDK source, not from this issue:
---title: "Send Message Tool"sidebarTitle: "Send Message"description: "Let agents proactively message the user through Telegram, Slack, Discord, and other gateways mid-task"icon: "paper-plane"---{/* One-sentence intro */}
Send Message lets a running agent reach the user proactively on their configured channels — \"I've finished the report, sending it to you on Telegram\" — without waiting for the next user turn.
{/* Hero diagram — see §3 below */}## Quick Start
<Steps>
<Steptitle="Enable the tool"> ... agent-centric minimal example ... </Step>
<Steptitle="List reachable targets"> ... send_message(action=\"list\") ... </Step>
<Steptitle="Send with attachments"> ... MEDIA:/path example ... </Step>
</Steps>
---## How It Works{/* sequence diagram: Agent → send_message → OutboundMessenger → Gateway → User */}{/* short table: tool / messenger protocol / gateway registers it */}---## Targets{/* table of target forms: origin / <platform> / <platform>:<chat_id>[:<thread_id>] / alias */}{/* small \"choose your target\" mermaid graph */}---## Attachments (MEDIA:){/* explain MEDIA:<path> directive, multiple supported, path can contain no whitespace */}---## Listing Targets{/* show action=\"list\" + sample JSON */}---## When It's Available{/* gateway/bot: yes. CLI one-shot: no — returns the no-gateway string, doesn't raise. */}{/* short table: runtime → behaviour */}---## User Interaction Flow{/* per AGENTS.md §1.1 rule 11 — narrate a real scenario: User starts a long-running task on Telegram → leaves chat → agent finishes report → agent calls send_message(\"origin\", \"Done MEDIA:/tmp/r.pdf\") → user gets a Telegram push with the file. */}---## Configuration Reference{/* Link to auto-gen SDK reference once it's generated for messaging_tools. Until then, just the args table above. Do NOT duplicate full SDK signatures. */}---## Common Patterns{/* 2–3: notify on long task completion; cross-channel handoff; pick target from list first */}---## Best Practices
<AccordionGroup>
<Accordiontitle=\"Alwaysconfirmchannelbeforesending\">...</Accordion><Accordiontitle=\"Use'origin'bydefault\">...</Accordion><Accordiontitle=\"Handletheno-gatewayfallbackininstructions\">...</Accordion><Accordiontitle=\"Keepmessagesshort—theyhitaphone\">...</Accordion></AccordionGroup>---##Related<CardGroupcols={2}>
<Cardtitle=\"ClarifyTool\"href=\"/docs/features/clarify-tool\">Asktheusermid-task</Card><Cardtitle=\"ChannelsGateway\"href=\"/docs/features/channels-gateway\">ConnecttoTelegram/Slack/Discord/WhatsApp</Card><Cardtitle=\"BotGateway\"href=\"/docs/features/bot-gateway\">Runthegatewayserver</Card><Cardtitle=\"BotRouting\"href=\"/docs/features/bot-routing\">Routemessagesbychannel</Card></CardGroup>
Hero diagram (use this exact mermaid block — matches §3 color scheme)
graph LR
subgraph "Send Message Flow"
A[🤖 Agent] --> B[📤 send_message]
B --> C[🛰️ Gateway]
C --> D[📱 User]
end
classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff
classDef tool fill:#189AB4,stroke:#7C90A0,color:#fff
classDef gateway fill:#F59E0B,stroke:#7C90A0,color:#fff
classDef user fill:#10B981,stroke:#7C90A0,color:#fff
class A agent
class B tool
class C gateway
class D user
Loading
"How it works" sequence diagram
sequenceDiagram
participant Agent
participant SendMessage as send_message
participant Context as SessionContext
participant Messenger as OutboundMessenger
participant Gateway
participant User
Agent->>SendMessage: send_message("origin", "Done MEDIA:/tmp/r.pdf")
SendMessage->>Context: get_outbound_messenger()
Context-->>SendMessage: messenger (or None)
alt no gateway
SendMessage-->>Agent: "No active gateway: ..."
else gateway active
SendMessage->>Messenger: send(target, text, media=[...])
Messenger->>Gateway: deliver
Gateway->>User: push (Telegram/Slack/etc.)
Messenger-->>SendMessage: DeliveryResult(ok, target, summary)
SendMessage-->>Agent: summary
end
Loading
Code examples to include (verify each runs)
1. Agent-centric Quick Start (top of page — per AGENTS.md §1.1 rule 9):
frompraisonaiagentsimportAgentfrompraisonaiagents.toolsimportsend_messageagent=Agent(
name="Reporter",
instructions="When you finish a long task, message the user on their channel.",
tools=[send_message],
)
agent.start("Generate the weekly report and notify me when it's ready.")
2. List targets first:
# The model calls:# send_message(action="list")# and gets back JSON like:# [{"target": "telegram:home", "platform": "telegram", "kind": "home", "label": "Telegram"}]
3. Send with media attachment:
# Model call:# send_message("origin", "Weekly report ready MEDIA:/tmp/report.pdf")# Returns: "Delivered to origin"
4. Explicit channel target:
# Model call:# send_message("slack:#ops", "Deploy finished ✅")
Concepts to explain (per AGENTS.md §6 — for non-developers)
Every concept on the page gets one short sentence + (if useful) a small mermaid diagram:
"origin" vs explicit target vs alias — small decision-style mermaid graph so the reader knows which to use when. AGENTS.md §6.1: "If multiple options in one page, people might be confused on what to choose, so create the mermaid diagram to choose what option at what instance."
MEDIA: directive — one sentence + a one-line example.
action="send" vs action="list" — one-line comparison table.
Writing rules (recap from AGENTS.md §6)
One-sentence section intros. No "In this section..." / "As you can see..." / "Let's take a look at...".
Active voice. Direct. Specific.
Agent-centric examples at the top.
Non-developers must feel "is it really this easy?" after reading.
Use friendly imports: from praisonaiagents.tools import send_message (not deep submodule paths).
docs.json update
After creating the file, add to docs.json under the Features group:
"docs/features/send-message-tool"
Place it near the other agent-tool / gateway feature entries (e.g. next to docs/features/clarify-tool and the gateway pages). Do NOT add under the Concepts group. Validate the JSON after editing.
Source change
PraisonAI PR: MervinPraison/PraisonAI#2188 (merged — fixes #2183)
Adds a new agent-facing built-in tool:
send_message. Lets a running agent proactively reach the user mid-task on the channel the conversation came from (or any other configured channel) through the existing gateway delivery stack — and list reachable targets.Before this change, proactive delivery was only reachable from the scheduler or the
gateway sendCLI; an agent had no way to message the user during a task.Doc action required
Type: NEW PAGE (no existing docs page covers this; existing
send_messagereferences in the docs are about bot adapter methods, not the new agent-facing tool).File to create:
docs/features/send-message-tool.mdxFolder:
docs/features/(per AGENTS.md §1.8 — neverdocs/concepts/).Pattern to mirror:
docs/features/clarify-tool.mdx— same shape (agent-facing built-in that resolves a per-turn handler/messenger from context; fails cleanly when not available).Add to
docs.json: under the Features group, NEVER under Concepts. Do not modify auto-generateddocs/js/ordocs/rust/entries.SDK ground truth (read before writing)
The implementation agent MUST read these files in
MervinPraison/PraisonAIbefore writing the page (per AGENTS.md §1.2 SDK-first cycle):praisonaiagents/tools/messaging_tools.pypraisonaiagents/tools/__init__.pypraisonaiagents/gateway/protocols.py(OutboundMessengerProtocol,DeliveryResult,TargetInfo)praisonaiagents/session/context.py(register_outbound_messenger,get_outbound_messenger,clear_outbound_messenger,register_gateway_loop,get_gateway_loop,clear_gateway_loop)tests/unit/tools/test_send_message_tool.pyThe PR description is here: MervinPraison/PraisonAI#2188
Verify all values against source — don't copy any spec from this issue without confirming it.
Public API (from SDK)
Import
Function signature
Arguments
targetstr"origin""origin"(chat the conversation came from),"<platform>"(platform's home channel, e.g."telegram"),"<platform>:<chat_id>[:<thread_id>]"(explicit chat), or a friendly alias for a known target.messagestr""" MEDIA:<path>"one or more times to attach local files, e.g."Report ready MEDIA:/tmp/report.pdf".actionstr"send""send"to deliver a message, or"list"to return a JSON array of reachable targets.Returns
action="send": human-readable summary string (e.g."Delivered to slack:#ops", or"Failed to send to ...: <detail>").action="list": JSON string of[{target, platform, kind, label}, ...]—kindis one of"origin","home","alias".When it's available
Available when running inside a gateway/bot (Telegram, Slack, Discord, WhatsApp, etc.) — the gateway registers an
OutboundMessengerProtocolimpl into the per-turn context.Unavailable for plain CLI / one-shot runs. The tool does not raise — it returns the literal string:
This graceful-fallback behaviour must be documented (mirror how
clarify-tool.mdxdocuments its fallback).Required page structure (per AGENTS.md §2)
Use this exact skeleton. Fill from SDK source, not from this issue:
Hero diagram (use this exact mermaid block — matches §3 color scheme)
graph LR subgraph "Send Message Flow" A[🤖 Agent] --> B[📤 send_message] B --> C[🛰️ Gateway] C --> D[📱 User] end classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff classDef tool fill:#189AB4,stroke:#7C90A0,color:#fff classDef gateway fill:#F59E0B,stroke:#7C90A0,color:#fff classDef user fill:#10B981,stroke:#7C90A0,color:#fff class A agent class B tool class C gateway class D user"How it works" sequence diagram
sequenceDiagram participant Agent participant SendMessage as send_message participant Context as SessionContext participant Messenger as OutboundMessenger participant Gateway participant User Agent->>SendMessage: send_message("origin", "Done MEDIA:/tmp/r.pdf") SendMessage->>Context: get_outbound_messenger() Context-->>SendMessage: messenger (or None) alt no gateway SendMessage-->>Agent: "No active gateway: ..." else gateway active SendMessage->>Messenger: send(target, text, media=[...]) Messenger->>Gateway: deliver Gateway->>User: push (Telegram/Slack/etc.) Messenger-->>SendMessage: DeliveryResult(ok, target, summary) SendMessage-->>Agent: summary endCode examples to include (verify each runs)
1. Agent-centric Quick Start (top of page — per AGENTS.md §1.1 rule 9):
2. List targets first:
3. Send with media attachment:
4. Explicit channel target:
Concepts to explain (per AGENTS.md §6 — for non-developers)
Every concept on the page gets one short sentence + (if useful) a small mermaid diagram:
MEDIA:directive — one sentence + a one-line example.action="send"vsaction="list"— one-line comparison table.Writing rules (recap from AGENTS.md §6)
from praisonaiagents.tools import send_message(not deep submodule paths).docs.json update
After creating the file, add to
docs.jsonunder the Features group:"docs/features/send-message-tool"Place it near the other agent-tool / gateway feature entries (e.g. next to
docs/features/clarify-tooland the gateway pages). Do NOT add under the Concepts group. Validate the JSON after editing.Acceptance checklist (per AGENTS.md §9)
docs/features/send-message-tool.mdxtitle,sidebarTitle,description,icon: "paper-plane"<Steps>with agent-centric example firstactionpaths shown: implicit send /action="send"/action="list"MEDIA:directive documented with at least one exampleorigin,<platform>,<platform>:<chat_id>[:<thread_id>], alias<AccordionGroup>Best Practices section<CardGroup>Related section with at least Clarify Tool + Channels Gateway + Bot Gatewaydocs.jsonunder Features (not Concepts); valid JSONdocs/concepts/,docs/js/,docs/rust/your-key-hereplaceholders)from praisonaiagents.tools import send_messagepraisonaiagents/tools/messaging_tools.pyandpraisonaiagents/gateway/protocols.pyOut of scope (do NOT include)
_run_asyncthread/loop handling — that's implementation, not user-facing.BotOutboundMessengerimplementation details — belongs in a separate gateway-internals page if needed.docs/sdk/reference/**— that tree is auto-generated.