Skip to main content
Bot run control provides responsive feedback during long-running agent tasks, eliminating silent blocking where follow-up messages queue invisibly.

Quick Start

1

Enable Run Control

from praisonaiagents import Agent
from praisonai.bots import TelegramBot

agent = Agent(name="assistant", instructions="Be helpful")
bot = TelegramBot(token="YOUR_TOKEN", agent=agent, busy_mode="interrupt")

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

Test with Long Task

Send a long-running request like “research solar energy trends” to your bot, then immediately send another message. You’ll get instant feedback instead of silence.
3

Try /stop Command

While the bot is working, send /stop to cancel the current task. The bot responds immediately and starts fresh.

How It Works

Fixed in PR #1980 (release after 2026-06-19): earlier releases wired the interrupt controller to the wrong attribute, so /stop and busy_mode="interrupt" silently had no effect. Queued follow-ups were surfaced in metadata but never drained — upgrade to pick up the fix.
When run_timeout is exceeded (default 300 seconds), BotSessionManager raises BotRunTimeout and cancels the in-flight run. Timeout failures are not pushed to the DLQ, so slow agents do not retry in a loop.

Choosing a Busy Mode

ModeWhen to UseBehavior
queueResearch bots, task completion importantMessages queued, processed in order after current task
interruptInteractive chat, latest intent mattersCancels current task, starts new one immediately
steerReal-time collaboration (experimental)Injects messages into running task (fallback to queue)

Configuration Options

Configure run control through BotConfig or directly with bot constructors:
from praisonaiagents import Agent
from praisonai.bots import TelegramBot

# Via bot constructor
bot = TelegramBot(
    token="YOUR_TOKEN",
    agent=agent,
    busy_mode="queue",
    busy_ack="🕒 Got it — {action}. I'll handle it after this finishes."
)
OptionTypeDefaultDescription
busy_modestr"queue"Policy for mid-run messages. One of "queue", "interrupt", "steer".
busy_ackstr"⏳ {action} — will be considered next"Template for busy acknowledgment. {action} is replaced with "noted" (queued) or "added to pending request" (merged).
run_timeoutfloat300.0Maximum seconds a single agent run may take before it is cancelled with BotRunTimeout. Set to 0 or a negative value to disable. Applies to both streaming (agent.astart) and non-streaming (agent.chat) paths.

Run metadata

chat_with_run_control returns {"response": str, "metadata": dict}:
FieldTypeDescription
run_controlboolAlways True when run control was active.
decisionstrInitial decision: "RUN_NOW", "QUEUED", or "INTERRUPTED".
completedboolTrue after the run and drain loop finish cleanly.
run_generationintGeneration counter for race protection.
pending_processedlist[str]Queued follow-ups drained after the initial run (each truncated to 100 chars). Present only when at least one was processed.
interruptedboolTrue if the run was cancelled mid-way.
reasonstrCancellation reason (when interrupted is True).
Queue drain implemented in PR #1980.

Programmatic cancellation

BotSessionManager exposes cancellation for admin hooks or custom integrations:
from praisonaiagents import Agent
from praisonai.bots import TelegramBot

agent = Agent(name="assistant", instructions="Be helpful")
bot = TelegramBot(token="YOUR_TOKEN", agent=agent)

# Cancel a specific user's in-flight run (e.g. from an admin endpoint)
bot._session.cancel_run(user_id="123456789", reason="admin_kill")

# See who has a run in progress right now
print(bot._session.get_active_runs())
MethodReturnsDescription
cancel_run(user_id, reason="user_cancel")boolTrue if an active run existed and was signalled
get_active_runs()list[str]Storage keys with runs currently in progress

BotConfig API Reference

Full configuration options for bot settings

Common Patterns

Long Research Bot (Queue Mode)

from praisonaiagents import Agent
from praisonai.bots import TelegramBot

agent = Agent(
    name="researcher", 
    instructions="Research topics deeply and provide comprehensive analysis"
)

bot = TelegramBot(
    token="YOUR_TOKEN",
    agent=agent,
    busy_mode="queue",  # Preserves work — all follow-ups drained in order after each run
    busy_ack="📚 Research noted — {action}. Will incorporate after analysis."
)

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

Interactive Chat Bot (Interrupt Mode)

from praisonaiagents import Agent
from praisonai.bots import TelegramBot

agent = Agent(name="assistant", instructions="Be helpful and responsive")

bot = TelegramBot(
    token="YOUR_TOKEN",
    agent=agent,
    busy_mode="interrupt",  # Latest message wins
    busy_ack="{action} — switching to your latest request"
)

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

Using /stop Mid-Task

When a bot is processing a long request:
User: research quantum computing applications
Bot:  (working...)
User: /stop
Bot:  ✅ Current task cancelled. Send a new message to start fresh.
User: what's the weather?
Bot:  (starts new task immediately)

Best Practices

Use queue mode for bots that do important work users shouldn’t lose — research bots, analysis tools, content generators. Users get acknowledgments but work continues.Use interrupt mode for conversational bots where the latest message reflects user intent — chat assistants, Q&A bots, real-time helpers.Use steer mode (experimental) for collaborative scenarios where users provide guidance during long tasks. Currently falls back to queue mode.
/stop works on stock bots without setting busy_mode. The handler tries SessionRunControl.stop() first when run control is enabled, then falls back to BotSessionManager.cancel_run() on the default session manager. Enable run control (busy_mode) when you also want mid-run pending-message handling — not as a prerequisite for /stop.
Each run gets a unique generation number. When a run finishes, it only clears the session state if its generation matches the current one. This prevents cancelled runs from overwriting fresh state when they complete.
Use SessionRunControl.cleanup_stale_sessions(max_age_seconds=3600) to clean up old sessions. This prevents memory leaks in long-running bots and removes abandoned user sessions.
If you embed BotSessionManager.chat_with_run_control() in a custom bot, attach interrupt controllers to agent.interrupt_controller (the public attribute on Agent). An earlier underscore-prefixed name was unreliable and made /stop a no-op for custom integrations. The built-in bots (TelegramBot, etc.) handle this attachment automatically.

Bot Commands

Built-in chat commands including /stop

Messaging Bots

Complete guide to Telegram, Discord, Slack bots