Ask Conversation Tool

Let agents ask another chat a question mid-turn and act on the reply — timeout-bounded, never hangs

Ask Conversation lets a running agent send a prompt to another chat, wait for that chat’s reply, and act on it — bounded by a timeout so a turn never hangs silently.

python
from praisonaiagents import Agent
from praisonaiagents.tools import ask_conversation

agent = Agent(
    name="Deploy Coordinator",
    instructions=(
        "Before deploying, ask #ops on Slack whether staging is green. "
        "If they reply 'yes', run the deploy. Otherwise, wait."
    ),
    tools=[ask_conversation],
)
agent.start("Deploy build 42.")

A user asks the agent to ship a build; the agent asks another channel whether it’s safe, waits for the reply, and acts on the answer — all within a single turn.

Diagram

Ask Conversation Flow

🤖 Agent

❓ ask_conversation

🛰️ Gateway

💬 Target Chat

Which tool?

ask_conversation is easy to confuse with its two siblings. This decision diagram picks the right one.

Diagram

Yes — need input from them

No — talking to another chat/agent

No — just deliver

Yes — wait for reply

Which tool?

Talking to the current user?

clarify_tool

Need their reply?

send_message

ask_conversation

ToolDirectionWaits for reply?Availability
clarify_toolTo the current userYesAny runtime
send_messageTo any targetNo (fire-and-deliver)Bot / gateway only
ask_conversationTo any targetYes (bounded, typed outcome)Bot / gateway only

Quick Start

  1. Ask One Question
    python
    from praisonaiagents import Agent
    from praisonaiagents.tools import ask_conversation
    
    agent = Agent(
        name="Coordinator",
        instructions="Ask #ops on Slack if staging is green before deploying.",
        tools=[ask_conversation],
    )
    
    agent.start("Deploy build 42.")
    # Model call:
    #   ask_conversation("slack:#ops", "Is staging green for build 42?")
    # Returns JSON:
    #   {"status": "reply", "from": "slack:#ops", "text": "yes, staging is green"}
  2. Adjust the Timeout for Slower Channels
    python
    # Give an on-call human longer to answer than a live chat.
    #   ask_conversation("slack:#oncall", "Approve deploy 42?", timeout_s=600)

    Default wait is 120 seconds. Raise timeout_s for humans who may be away; the hard cap is 3600 seconds.

  3. Handle the Four Outcomes in Instructions
    python
    agent = Agent(
        name="Coordinator",
        instructions=(
            "Ask #ops if it's OK to deploy. "
            "If status is 'reply' and they say yes, deploy. "
            "If status is 'timeout', 'undelivered', or 'no_route', "
            "do not deploy — report the reason to the user instead."
        ),
        tools=[ask_conversation],
    )

    Every call resolves to exactly one typed outcome, so tell the agent what to do for each.


How It Works

ask_conversation sends the prompt through the same delivery stack send_message uses, then waits for the next reply that correlates back from the target — returning it as a JSON string.

Diagram
💬 Target ChatGatewayConversationRequesterSessionContextask_conversationAgent💬 Target ChatGatewayConversationRequesterSessionContextask_conversationAgentalt[no gateway][gateway active]ask_conversation(“slack:get_conversation_requester()requester (or None)“No active gateway: …”ask(target, text, timeout_s)deliver + await replypromptreplycorrelated replyConversationReplyJSON string (status + fields)
ComponentPurpose
ask_conversation toolAgent-callable function; resolves the requester from context
ConversationRequestProtocolInterface the gateway registers per-turn to send-and-await
SessionContext slotTask-local register_conversation_requester — no globals, safe for concurrent handlers
Send Policy GuardSame policy that gates send_message; deny → undelivered before dispatch
GatewayDelivers to Telegram, Slack, Discord, WhatsApp, etc., and correlates the reply

The reply is matched back to the request via the existing correlation-id infrastructure.


Outcomes

Every call resolves to exactly one of four typed statuses, so a turn never hangs silently.

statusMeaningExtra fields
"reply"Target answered within timeout_sfrom, text, optionally detail
"timeout"Delivered, but no reply within timeout_soptionally from, detail
"undelivered"Prompt could not be delivered (send policy denied it, or the requester raised)detail explains why
"no_route"Target could not be resolved to a reachable channel—
json
{"status": "reply", "from": "slack:#ops", "text": "yes, staging is green"}
json
{"status": "timeout"}
json
{"status": "undelivered", "detail": "Sending to 'slack:#exec' is not permitted by the current send policy."}
json
{"status": "no_route"}

Targets

Targets use the same forms as send_message — see Send Message → Targets.


Timeouts (bounded wait)

timeout_s sets the maximum seconds the tool waits for a reply, and the value is normalized so a turn can never wait forever.

Input to timeout_sResult
Omitted120.0 (default)
NaN, +inf, -infFalls back to 120.0
≤ 0 or non-numericFalls back to 120.0
> 3600Clamped to 3600.0

The target is model-controlled, so the tool refuses to let a prompt-injected agent make a turn wait indefinitely — this clamp is a security property, not a suggestion.


When It’s Available

ask_conversation needs a running bot/gateway to reach another chat and correlate its reply.

Diagram

Yes — Telegram, Slack, Discord, etc.

No — CLI or one-shot run

Runtime

Gateway running?

✅ ask_conversation works

⚠️ Returns no-gateway message

RuntimeBehaviour
Bot / Gateway (Telegram, Slack, Discord, WhatsApp, …)Sends the prompt and awaits a reply; returns a typed JSON string
CLI / one-shot (agent.start(...) directly)Returns the string below — does not raise

When no gateway is active the tool returns:

No active gateway: ask_conversation is only available inside a running bot/gateway (e.g. Telegram, Slack, Discord). It is unavailable for CLI/one-shot runs.

User Interaction Flow

A Telegram user asks the deploy agent to ship build 42. Before running the deploy, the agent calls ask_conversation("slack:#ops", "OK to deploy build 42?"). #ops replies “green — go ahead” in Slack. The agent proceeds with the deploy and reports success back to the user on Telegram.

Diagram
💬 Slack🤖 Agent📱 User (Telegram)💬 Slack🤖 Agent📱 User (Telegram)“Deploy build 42”ask_conversation(“slack:{“status”: “reply”, “text”: “green — go ahead”}Run the deploy“Deployed build 42 ✅ (ops approved)”

Configuration Reference

ask_conversation takes three arguments:

ArgumentTypeDefaultDescription
targetstrrequiredSymbolic destination — same forms as send_message: "origin", "<platform>", "<platform>:<chat_id>[:<thread_id>]", or a friendly alias.
textstr""The prompt to send to target.
timeout_sfloat120.0Max seconds to wait for a reply. Non-numeric, non-finite (NaN / ±inf), or non-positive falls back to 120s; anything above 3600s is clamped to 3600s.

Returns: a JSON string of the reply — one of the four statuses above.


Common Patterns

Human-in-the-loop approval on another platform

python
agent = Agent(
    name="Deployer",
    instructions=(
        "Before deploying, ask #ops on Slack for approval. "
        "Only deploy if they reply yes."
    ),
    tools=[ask_conversation],
)
# Model call:
#   ask_conversation("slack:#ops", "Approve deploy of build 42?")

Cross-agent handoff

python
agent = Agent(
    name="Writer",
    instructions="Ask the research agent for the latest revenue number, then use it.",
    tools=[ask_conversation],
)
# Model call:
#   ask_conversation("slack:#research", "What's the latest Q3 revenue figure?")

Graceful fallback on non-reply outcomes

python
agent = Agent(
    name="Coordinator",
    instructions=(
        "Ask #ops before deploying. "
        "If ask_conversation returns status other than 'reply', "
        "skip the deploy and tell the user why."
    ),
    tools=[ask_conversation],
)

Best Practices

Prefer ask_conversation over polling

The wait is bounded and correlated — you get exactly one typed outcome. Don’t loop send_message and re-check for a reply; ask_conversation handles the send-and-await for you.

Right-size timeout_s

Keep it short for humans in a live channel, longer for on-call escalations. The hard cap is 3600s — anything higher is clamped.

python
# Live channel — a few minutes
ask_conversation("slack:#ops", "OK to deploy?", timeout_s=180)

# On-call escalation — up to the 3600s cap
ask_conversation("slack:#oncall", "Approve emergency fix?", timeout_s=3600)
Handle all four outcomes in agent instructions

Include a line like _”If ask_conversation returns status ≠ ‘reply’, fall back to X”_ so reply, timeout, undelivered, and no_route are all covered.

Restrict targets with SendPolicy

Use SendPolicy to limit which channels an agent may ask. A denied policy returns undelivered before the message goes out, so the target chat is never contacted.


Related